Introducción a C Gorka Guardiola Múzquiz paurea@lsub.org © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 1 C C no hace nada automáticamente como lenguaje (lo mínimo) Si no entiendo algo de C me va a morder C es relajado, tengo que ser ordenado C es fácil de entender completamente © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 2 Primer programa #include <u.h> #include <libc.h> //comentario en una linea /* comentario en mas de una linea*/ void main(int argc, char *argv[]) { print("hello world\n"); exits(nil); } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 3 Punto de entrada #include <u.h> #include <libc.h> →void →main(int argc, char *argv[]) { print("hello world\n"); exits(nil); } main es el punto de entrada del programa Es una función con un prototipo concreto y un nombre especial main © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 4 Punto de entrada #include <u.h> #include <libc.h> void main(int argc, char *argv[]) { print("hello world\n"); exits(nil); } No devuelve nada (void), recibe dos parámetros Dos partes, cabecera/prototipo y cuerpo El cuerpo es un bloque, entre llaves Dentro van más bloques, entre llaves O sentencias acabadas en ; © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 5 funciones #include <u.h> #include <libc.h> void main(int argc, char *argv[]) { → print("hello world\n"); exits(nil); } print es una función Se usa para imprimir por pantalla © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 6 Antes de usar funciones de librería Primero mirar en la página de manual lookman para buscar si no sé qué busco $ lookman floppy $ lookman copy man N intro Introducción a la sección N del manual la 1 el sistema man N bla Para buscar bla en la sección N del manual $ man 2 print © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 7 manual Hay que buscar funciones y llamadas en la página de manual Nos interesan las secciones: Ë 1 comandos Ë 2 llamadas al sistema y funciones de librería man N intro Para información acerca de la sección N. © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 8 include Lo primero que viene es qué debo incluir →#include <u.h> →#include <libc.h> void main(int argc, char *argv[]) { print("hello world!"); exits(nil); } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 9 include Luego veremos más, pero: Ë Cada librería requiere unos include Ë En el orden que dice la página de manual Ë No repetidos Si miro en la página de manual, exits y print requieren u.h y libc.h. © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 10 Compilación, intro Primero se compila el fichero Ë $ 8c -FTVw main.c Ë Genera el objeto main.8 Si hubiese otros, se generan igual Ë $ 8c -FTVw bla.c Ë $ 8c -FTVw otro.c Luego se hace el enlazado (linking): Ë $ 8l -o programa main.8 otro.8 bla.8 Ë Los objetos de las librerías del sistema como libc se enlazan automáticamente sin que tengamos que decir nada © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 11 Compilación, intro El resultado es el programa ejecutable Para ejecutarlo: Ë $ ./programa Ë hello world! © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 12 Compilación, intro Errores y warnings Los errores son fatales (no compila) Los warnings no son fatales (compila) Compilación, intro El compilador se lo traga casi todo!!! Ojo, en C los warning son como errores!! Warnings comportamiento impredecible © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 13 C: tipos básicos, estructuras de control Gorka Guardiola Múzquiz paurea@lsub.org © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 1 Enteros #include <u.h> #include <libc.h> void main(int argc, char *argv[]) { int i; i = 10; print("hello world, %d\n", i); exits(nil); } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 2 Compilado y ejecutado $ 8c -FTVw main.c $ 8l -o main main.8 $ ./main hello world, 10 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 3 ¿Qué significa? int i; es la declaración. i es un entero. es la definición. reserva memoria para i aquí. i = 10; asigna 10 al entero ¡Ojo! las variables de la pila hay que inicializarlas © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 4 ¿Qué significa? print("hello world, %d\n", i); La función recibe una string (veremos más adelante) con el formato %d significa "me pones aquí el segundo argumento en decimal como si fuese un entero", la d es de decimal si hubiese otro parámetro, se pone otro formato y se mete como tercer parámetro © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 5 Se pueden hacer más cosas: #include <u.h> #include <libc.h> void main(int argc, char *argv[]) { int i, j; i = 10; print("i = %d\n", i); i = i+1; j = 35; print("i = %d, j vale %d\n", i, j); exits(nil); } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 6 Se pueden hacer más cosas: Compilado $ 8c -FTVw main.c $ 8l -o main main.8 Ejecutado $ ./main i =10 i = 11, j vale 35 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 7 El \n Al final del formato hemos puesto \n Algunos carácteres de control especiales se ponen con una notación especial El tabulador, por ejemplo es \t y nueva línea \n © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 8 Char, enteros más pequeños char c; c = 3; print("c vale %d\n", c); c = ’x’; print("c vale %c\n", c); $ 8c -FTVw main.c $ 8l -o main main.8 $ ./main c vale 3 c vale x © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 9 Char Son enteros, simplemente más pequeños (normalmente 1 byte) Se pueden asignar y usar con y como enteros Tienen un formato para print como carácteres %c Hay una forma especial de definir constantes entre comillas simples ’c’ Se puede indicar que un número en realidad es un carácter: ’\0’, es igual que 0 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 10 Tamaños de variables y tipos de dato C no define tamaños concretos de tipos Se debe usar siempre sizeof sizeof (tipo) me da el tamaño de un tipo, cuanto espacio hay reservado para él en memoria sizeof variable me da el tamaño de una variable Si meto un tipo más grande en uno más pequeño, hay sorpresas © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 11 Tamaños de variables y tipos de dato void main(int argc, char *argv[]) { int i; char c; print("sz char %d ", sizeof (char)); print("sz i %d\n", sizeof i); i = 342; c = i; print("c = %d\n", c); c = 300; print("c = %d\n", c); exits(nil); } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 12 Tamaños de variables y tipos de dato Compilando y ejecutando imprime: sz char 1 sz i 4 c = 86 c = 44 El char se ha desbordado!!!. El número que da está mal. Asignar un int a un char no da ningún warning!! © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 13 Operaciones y tipos con signo #include <u.h> #include <libc.h> void main(int argc, char *argv[]) { int i; i = 10; print("i vale %d\n", i); i = i-11; print("i = %d\n", i); exits(nil); } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 14 Operaciones y tipos con signo $ 8c -FTVw main.c $ 8l -o main main.8 $ ./main i vale 10 i = -1 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 15 Operaciones y tipos con signo Normalmente los enteros tienen signo Para todos los tipos enteros se puede especificar que tengan o no tengan signo signed o unsigned Sólo cambia las comparaciones (y shifts), no te protege Normalmente basta con usar int o char simplemente. © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 16 Operaciones y tipos con signo int i; unsigned int j; i = -10; print("i vale %d\n", i); j = i; print("j = %d\n", j); print("j = %u\n", j); Imprime: i vale -10 j = -10 j = 4294967286 De nuevo ningún warning ni protección ¡Ojo! El formato %u para imprimir sin signo © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 17 Operaciones variadas int i; i = 0; print("i++ vale %d\n", i++); print("++i vale %d\n", ++i); print("i vale %d\n", i); print("i = 3 vale %d\n", i = 3); i += 8; print("i vale %d\n", i); Imprime: i++ vale 0 ++i vale 2 i = 3 vale 3 i vale 11 Cada expresión devuelve un valor (incluyendo la asignación) © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 18 Postincremento es: primero valor luego se incrementa i++ Preincremento: primero incremento luego valor ++i Tambien hay predecremento y postdecremento −− Asignación: evalúa al valor que se asigna Ë a = 2 evalúa a 2 a = a + c; se puede poner cómo a += c; Hay para todos los operadores += *= /= etc. ojo las operaciones sobre enteros son enteras © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 19 Operaciones variadas int i; i = 13; i = i / 2; print("i vale %d\n", i); i = 13; i %= 2; print("i vale %d\n", i); i vale 6 i vale 1 / es la división entera % es el resto o módulo (mod) © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 20 Operaciones variadas No hay tipo booleano, un entero diferente de 0 es cierto 0 es falso Los operadores de comparación son <= >= == > < != Devuelven un entero que cumple lo de arriba © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 21 if if (0) print("es cierto\n")); else print("es falso"); Imprime: es falso la sentencia o bloque de sentencias del else se ejecutan si es falsa la condición. © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 22 Operaciones variadas int i; i = 13; if (i == 13){ print("es igual\n")); print("la la la\n"); } Imprime es igual la la la if considera el entero de forma lógica i == 13 es una expresión y como tal retorna un valor, algo diferente de 0 Se ejecuta el bloque, entre llaves. © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 23 Operaciones variadas int i; i = 13; if (i != 13) print("es igual\n")); print("la la la\n"); Imprime: la la la Obsérvese que el if solo afecta a una línea porque no hay llaves y la sentencia es sólo el print © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 24 Operaciones variadas Los operadores "lógicos" son && || ! if ((10 == 13) || (3 > 2) || 0) print("es cierto\n")); Imprime: es cierto © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 25 Operaciones variadas Los operadores sobre bits son: Ë ~ >> <<^ & | ^ ~ >> << ¡Ojo! & es diferente de && ¡Ojo! tienen poca precedencia Ë a&b == c agrupa a & (b == c) mejor no depender y poner paréntesis. print("%x\n", 0xff & ~0x1); fe Imprime: El formato %x imprime en hexadecimal & hace el bitwise and (| hace el or) ~ es not bit a bit << >> son shifts con signo (si el tipo es con signo) © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 26 Bucles int i; i = 10; while (i != 2){ print("i vale %d\n", i)); i/=2; } Imprime: i vale 10 i vale 5 Es un bucle que se ejecuta mientras dura la condición © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 27 Bucles int i; for(i = 0; i < 3; i++) print("i vale %d\n", i)); Imprime: i vale 0 i vale 1 i vale 2 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 28 Bucles El for de C no es un bucle al uso tiene dentro de los paréntesis dos sentencias cualesquiera y una expresión: Ë for(sentencia; expresión; sentencia){} la primera sentencia una vez al comenzar la comparación se evalúa al comenzar cada vuelta para ver si "se continúa la última sentencia al terminar cada vuelta conviene no ser innovador y utilizar "idioms" © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 29 Bucles, for y while equivalente El bucle: for(i = 0; i < 5; i++){ print("hola\n"); } Es equivalente a: i = 0; while(i < 5){ print("hola\n"); i++; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 30 break y continue break continue © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 31 continue int i; for(i = 0; i < 5; i++){ if(i == 3) continue; print("i vale %d\n", i)); } Imprime: i vale 0 i vale 1 i vale 2 i vale 4 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 32 break int i; i = 40; while (i != 2){ print("i vale %d\n", i)); i/=2; if(i < 20) break; } Imprime: i vale 40 i vale 20 i vale 10 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 33 Hay también un do while Como el while, pero entra una vez al menos do{ i++; }while (i < 2) © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 34 C: funciones, memoria Gorka Guardiola Múzquiz paurea@lsub.org © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 1 Funciones, declaración int mifuncion(int numero) { int otro; otro = 3; numero += otro; print("el num es: %d", numero); return otro; } mifuncion es una función como main recibe como parámetro un entero retorna un entero © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 2 Funciones, declaración si no retornase nada, el tipo es void si no recibe nada, el tipo es void ojo, void tiene otros significados © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 3 Cabecera, declaración la definición de una función tiene dos partes cabecera y cuerpo La cabecera declara la función, da su tipo El bloque de código es el cuerpo (entre {}) similar a la declaración/definición de un int Ë declaración cabecera, "tipo argumentos, tipo resultado" Ë en un int sería "esta variable es int" Ë definición código (entre {}) Ë en un int sería "reserva aquí sizeof(int) bytes" Se puede escribir la cabecera sola: int mifuncion(int numero); véase el ; © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 4 Cabeceras y tipos de datos No se puede usar una función sin haberla declarado antes, la cabecera, o entera en el fichero o en otros que se incluyen antes que éste. Esto no es especial para funciones El compilador necesita haber visto el tipo de datos antes de usarlo para hacer comprobaciones. El enlazador sólo mira símbolos, no comprueba tipos (bueno, salvo por el -T). © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 5 Uso de la función void main(int argc, char *argv[]) { mifuncion(4); exits(nil); } int mifuncion(int numero) { int otro; otro = 3; numero += otro; print("el num es: %d", numero); return otro; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 6 Uso de la función Compilo: $8c -FTVw func.c $8l -o func func.o bla.c:8: function args not checked: mifuncion © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 7 Así sí int mifuncion(int numero) { int otro; otro = 3; numero += otro; print("el num es: %d", numero); return otro; } void main(int argc, char *argv[]) { mifuncion(4); exits(nil); } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 8 Así tambien int mifuncion(int numero); void main(int argc, char *argv[]) { mifuncion(4); exits(nil); } int mifuncion(int numero) { int otro; otro = 3; numero += otro; print("el num es: %d", numero); return otro; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 9 La memoria cat /proc/12/segment © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 10 0x00001000-0x0002e000 Text Segment R 0x0002e000-0x00037000 Data Segment 0x00037000-0x0017d000 Bss 0xdefff000-0xdffff000 Stack/Pila © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 11 La memoria Los números son direcciones de memoria (no nos importan mucho cuales concretamente, sino su organización) Una idea de la situación y cómo funciona Pila/stack, montón/heap, texto, datos. © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 12 ¿Dónde va la memoria? 0x00001000- Textcódigo 0x0002e000- Dataglobales i. 0x00037000- Bssglobales n.i. - BssHeap 0xdefff000- Stacklocales © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 13 La memoria La flecha indica lo que voy a ejecutar, PC #include <u.h> #include <libc.h> int global; void main(int argc, char *argv[]) { → global = 2; global = 4; exits(nil); } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 14 La memoria Texto PC global = 2 global = 4 exits(nil); Datos ............................................................................................................................................. global © Gorka Guardiola Múzquiz C Introducción 0 Mar 4, 2009 Pg. 15 La memoria #include <u.h> #include <libc.h> int global; void main(int argc, char *argv[]) { global = 2; → global = 4; exits(nil); } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 16 La memoria Texto PC global = 2 global = 4 exits(nil); Datos ............................................................................................................................................. global © Gorka Guardiola Múzquiz C Introducción 2 Mar 4, 2009 Pg. 17 La memoria y las funciones ¿Y la memoria de las funciones?. Argumentos y variables locales van a la pila El valor de retorno va en un registro (AX, en intel) © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 18 Uso de la función en ejecución void main(int argc, char *argv[]) { → mifuncion(4); exits(nil); } int mifuncion(int numero) { numero = 3; return 1; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 19 La memoria Texto main PC mifuncion(4); exits(nil); mifuncion numero = 3; return 1; ............................................................................................................................................. Pila ... SP © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 20 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 21 Uso de la función en ejecución void main(int argc, char *argv[]) { mifuncion(4); exits(nil); } int mifuncion(int numero) { → numero = 3; return 1; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 22 Texto main PC mifuncion mifuncion(4); exits(nil); numero = 3; return 1; Pila ............................................................................................................................................. ... SP numero 4 PC (el exit) © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 23 Uso de la función en ejecución void main(int argc, char *argv[]) { mifuncion(4); exits(nil); } int mifuncion(int numero) { numero = 3; → return 1; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 24 Texto main mifuncion(4); exits(nil); mifuncion PC Pila numero = 3; return 1; ............................................................................................................................................. ... SP numero 3 PC (el exit) © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 25 Uso de la función en ejecución void main(int argc, char *argv[]) { mifuncion(4); → exits(nil); } int mifuncion(int numero) { numero = 3; return 1; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 26 Texto main PC mifuncion mifuncion(4); exits(nil); numero = 3; return 1; ............................................................................................................................................. Pila ... numero SP © Gorka Guardiola Múzquiz C Introducción 3 PC (el exit) Mar 4, 2009 Pg. 27 Observaciones La pila no se borra, sólo avanza y retrocede el puntero de pila, SP, sobreescribiendo las antiguas posiciones. El valor de retorno no está en la pila sino en un registro (AX en un PC). Nuestra función no tiene variables locales, pero si las tuviese también van a la pila, como ya hemos visto. © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 28 Inicialización La pila viene a un valor cualquiera, hay que inicializar Las variables globales siempre están inicializadas a 0 (salvo que las inicialice). Se inicializa poniendo, por ejemplo: int a = 3; © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 29 C: tipos compuestos, punteros, módulos Gorka Guardiola Múzquiz paurea@lsub.org © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 1 struct Son como los registros de Pascal/Ada Tipos de datos definidos por el usuario Agregan otros tipos de datos © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 2 Ejemplo: struct int int }; struct Point{ x; y; Point p; void mifuncion(void) { p.x = 3; p.y = 4; print("P is [%d. %d]\n", p.x, p.y); } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 3 Explicación del ejemplo: Son 3 partes Declaración del tipo (struct Point) Declaración/definición de la variable (p) Uso (p.x) © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 4 Explicación del ejemplo: Declaración del tipo (struct Point) struct Point{ int x; int y; }; Esto declara un tipo de datos (como int) El tipo de datos se llama struct Point sizeof (struct Point) es la suma de sizeof de los campos © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 5 Explicación del ejemplo: Declaración/definición de la variable (p) struct Point p; Como cualquier otra variable, es un trozo de memoria La struct en sí no ocupa, es como si me declarase cada uno de los tipos que contiene sueltos. © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 6 Explicación del ejemplo: Si, por ejemplo me declaro estas dos globales: struct Point p; struct Point q; © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 7 Explicación del ejemplo: La memoria Bss p q x 0 y 0 x 0 y 0 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 8 Explicación del ejemplo: La memoria sizeof(struct Point) = = sizeof(int) + sizeof(int) struct Point{ int x; int y; }; © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 9 Explicación del ejemplo: Uso p.x = 3; Accedo a los campos desde la variable con . © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 10 Una struct dentro de otra struct Rect{ struct Point ul; struct Point dr; }; struct Rect r; void otrafunc(void) { r.ul.x = 3; r.dl.y = 4; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 11 typedef, malo typedef es una forma de dar otros nombres No define tipos, sólo les da nombres En general, mala idea Ë Especialmente mala idea esconder * © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 12 typedef, útil struct Nombre Nombre, más corto Convenio para saber qué son structs Ë En Plan 9, con mayúsculas Nombre Se puede hacer typedef struct Nas Nas; sin haber definido la struct Nas; © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 13 typedef: ejemplo typedef struct Point Point; struct Point{ int x; int y; }; Point p; void otrafunc(void) { p.x = 3; print("sz Pnt %d", sizeof (Point)); } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 14 Constantes, enum La forma en C es usar enum enum { Total = 23, Nlitros = 42, }; Define valores enteros © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 15 Constantes, enum Se le puede dar nombre al tipo, pero no se usa mucho, es similar a typedef enum Colors { White = 0x0, Blue = 0x00ff00, }; © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 16 Constantes, enum Si no se le da valor, toma el anterior+1; El primero tiene valor 0 enum { Twrite, //vale 0 Tread, //vale 1 Topen = 28, Tclose, //vale 29 }; © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 17 punteros, introducción Un puntero en C se declara con un *. char *c; Un puntero no es más que un entero "especial" El tipo del puntero es (en el ejemplo) char * Otro ejemplo: int *i; Su tipo es int * © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 18 punteros, introducción Un puntero es una dirección de memoria que "apunta a otra" El puntero p apunta a la posición marcada como x p x 0x0000600c a n t e © Gorka Guardiola Múzquiz C Introducción 0x6000 0x6004 0x6008 0x600c 0x6010 Mar 4, 2009 Pg. 19 punteros Un puntero es un entero Apunta a otra variable, contiene su dirección Se pueden sumar y restar, con unas reglas especiales (aritmética de punteros). Hay un valor especial, nil (en realidad 0) que significa no apuntar a nada. © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 20 punteros, &, * La dirección de una variable se obtiene con & El contenido de la variable a la que apunta el puntero es * Por ejemplo: char *p; char c = ’a’; Y dentro de una función: p = &c; *p vale ’a’ © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 21 punteros, &, * La dirección de una variable se obtiene con & El contenido de donde apunta un puntero * p 0x00006004 0x6000 c a 0x6004 En el dibujo *p es ’a’ En el dibujo &c es 0x6004 p vale 0x6004 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 22 punteros, aritmética y tipo Un puntero apunta a un tipo de dato char * apunta a char Esto tiene dos consecuencias: Ë Si le sumo 1 al puntero, en realidad le sumo sizeof(tipo al que apunta) Ë El contenido del puntero es del tipo al que apunta © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 23 punteros, −> El operador p−>x para acceder a campos de struct Cuando tengo un puntero a la struct Es una forma mejor de escribir (*p).x Son completamente equivalentes © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 24 punteros, arrays No hay arrays de verdad en C. Hay una notación para declararse punteros constantes Y otra notación para indexar punteros © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 25 array, ejemplo char c[4]; En realidad c es un puntero constante que apunta a la primera posición del array, que son 4 posiciones de tamaño sizeof (char) c en sí no ocupa nada, es un valor constante. c 0x6000 0 0x6000 0 0x6004 0 0x6008 0 0x600c © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 26 array, ejemplo char c[27]; Estas dos sentencias: c[3] = ’t’; *(c+3) = ’t’; hacen lo mismo, c[3] es igual que *(c+3) funciona sobre punteros y sobre arrays, igual © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 27 punteros, strings No hay strings en C Hay una notación para inicializar la memoria de una forma especial "asassa" Por convenio un puntero a char en el que la memoria a la que apunta contiene carácteres y acaba en \0 se llama string. © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 28 Ejemplos de punteros, arrays, strings char gs[4] = "eco"; void mifuncion(void) { char *s; →s = gs; s[2] = ’c’; return; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 29 Texto Datos Pila PC mifuncion s = gs; s[2] = c; return; ... ............................................................................................................................................. gs 0x6040 e 0x6041 c 0x6042 o 0x6044 \0 ... ... ............................................................................................................................................. SP ... s: 0x587585 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 30 Ejemplos de punteros, arrays, strings char gs[4] = "eco"; void mifuncion(void) { char *s; s = gs; →s[2] = ’c’; return; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 31 Texto mifuncion s = gs; s[2] = c; PC return; ... ............................................................................................................................................. Datos gs 0x6040 e 0x6041 c 0x6042 o 0x6044 \0 ... ... ............................................................................................................................................. Pila SP ... s: 0x6040 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 32 Ejemplos de punteros, arrays, strings char gs[4] = "eco"; void mifuncion(void) { char *s; s = gs; →s[2] = ’c’; return; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 33 Texto mifuncion PC s = gs; s[2] = c; return otro; ... ............................................................................................................................................. Datos gs 0x6040 e 0x6041 c 0x6042 c 0x6044 \0 ... ... ............................................................................................................................................. Pila SP ... s: 0x6040 © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 34 punteros, strings, funciones strcmp, strncmp, strcpy, strlen, strncat mirar página de manual reciben char * memoria reservada!! al final del array un \0 (strings) © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 35 int strcmp(char *s1, char *s2) { unsigned c1, c2; for(;;) { c1 = *s1++; c2 = *s2++; if(c1 != c2) { if(c1 > c2) return 1; return -1; } if(c1 == 0) return 0; } } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 36 Ejemplos de punteros, arrays, strings long strlen(char *s) { long n; n = 0; while(*s++) n++; return n; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 37 Ejemplos de punteros, arrays, strings long strlen(char *s) { long n; for(n = 0; *s!= ’\0’; s++) n++; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 38 Ejemplos de punteros, arrays, strings long strlen(char *s) { long n; for(n = 0; s[n]!=’\0’; n++) ; return n; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 39 Ejemplos de punteros, arrays, strings long strlen(char *s) { return strchr(s, 0) - s; } © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 40 punteros, malloc, free, memset malloc pide un trozo de memoria en el montón (heap) la memoria que da malloc se puede usar hasta hacer free free le dice al que lo reserva que se lo puede asignar a otro (liberar) memset escribe un carácter n veces en memoria © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 41 Ejemplos de punteros, arrays, strings int *p; p = malloc(sizeof(int)*10); if(p == nil) ... manejo el error memset(p, 0, sizeof(int)*10); p[3] = 28; free(p); © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 42 Ejemplos de punteros, arrays, strings Siempre que llame a una función de librería/llamada al sistema Ë ver qué devuelve cuando hay un error Ë comprobar qué devuelve Ë manejar el error si no pone qué devuelve en caso de error Ë caso por defecto mirar intro(2) man 2 intro © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 43 punteros, broken, stack si intento acceder a una zona de memoria que no tengo permiso, el programa casca la primera página de memoria está protegida (de 0 a 4k) contra lectura y escritura. cualquier intento de atravesar * un puntero a nil, por ejemplo, casca © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 44 punteros, broken, stack $ ./hello hello 601: suicide: sys: trap: fault read addr=0x0 pc=0x00001261 $ ps|grep Broken paurea 601 0:00 0:00 24K Broken b Puedo ver su pila para ver dónde se quedó y a qué ha llamado con: $ stack hello • O también con el pid $ stack 601 No hace falta que esté roto © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 45 cast cast es convertir un tipo a otro los enteros promocionan unos a otros en C para el resto se puede hacer explícitamente (tú sabes lo que haces) poniendo el tipo entre paréntesis Por ejemplo: char *cp; int *ip; ip = (int *)cp; © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 46 void * sirve para apuntar a "cualquier cosa" es simplemente una dirección de memoria hay que hacer cast antes de usarlo la promoción void * → asdfa * es automática la promoción asdfa *→ void * requiere un cast © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 47 El preprocesador (cpp) todo lo que empieza con # hace sustituciones textuales antes de la compilación las sustituciones no rompen tokens © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 48 El preprocesador (cpp) #include Ë Mis .h, se buscan aquí #include <bla.h> Ë los .h del sistema, se buscan en /sys/include Ë es la forma estándar de usar librerías y demás Ë #include significa literalmente incluye ahí ese fichero No pongo includes en los .h! No pongo código en los .h, sólo declaraciones de tipos, constantes! © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 49 El preprocesador (cpp) #define Nbytes 3 Ë mejor usar enum #ifdef ... en general compilación condicional Ë mejor evitar (qué es lo que de verdad se compila?) © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 50 nm y el proceso de compilación La tabla de símbolos extern sólo declaración (necesito un símbolo) Ë alguien se ha declarado la variable en otro fichero extern int a; static local al ámbito (no exportes el símbolo) Ë nadie puede ver esta variable fuera de este ámbito (un fichero, por ejemplo) Ë variable en el segmento de datos (como una global, pero no se puede usar fuera) static int a; Ë para funciones y variables nm sobre objetos y ejecutables para imprimir la tabla de símbolos © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 51 Inicialización char *s = "hola"; es muy diferente de: char s[5] = "hola"; © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 52 Inicialización char *s = hola"; declara un puntero en la zona de datos reserva 5 caracteres consecutivos los rellena con con h o l a \0 mete en s la dirección del primer carácter. se puede hacer en dos pasos: Ë char *s; Ë s = "hola"; © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 53 Inicialización char s[5] = "hola"; no es una asignación (no se puede hacer en dos pasos) declara un array con su memoria "aquí" Ë si la variable es global datos Ë si la variable es local pila rellena la memoria con h o l a \0 el puntero no se puede modificar © Gorka Guardiola Múzquiz C Introducción Mar 4, 2009 Pg. 54