Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
INDICE 1.- INTRODUCCIÓN
3
CARACTERÍSTICAS FUNDAMENTALES ESTRUCTURA DE UN PROGRAMA C ELEMENTOS SINTÁCTICOS BÁSICOS ESTILO DE PROGRAMACIÓN
3 3 3 4
2.- TIPOS DE DATOS Y OPERADORES
6
TIPOS DE DATOS : VARIABLES : CONSTANTES : OPERADORES : CONVERSIÓN DE TIPO : TIPOS ENUMERADOS: DEFINICIÓN DE TIPOS :
6 6 8 9 10 11 11
3.- CONTROL DE FLUJO
14
EXPRESIONES Y SENTENCIAS : SENTENCIAS DE CONTROL DE FLUJO :
14 14
4.- FUNCIONES
18
CONCEPTOS BÁSICOS : DEFINICIÓN: DECLARACÍON: PROTOTIPOS DE FUNCIONES :
18 18 18 20
PARÁMETROS DE UNA FUNCIÓN:
21
RECURSIÓN: EL PREPOCESADOR DE C:
21 22
5.- PUNTEROS
29
PUNTEROS Y DIRECCIONES : DECLARACIÓN DE PUNTEROS : OPERADORES DE PUNTEROS: COMPARACIÓN DE PUNTEROS : ASIGNACIÓN DE PUNTEROS : PUNTEROS COMO PARÁMET RO DE FUNCIONES : ARITMÉTICA DE PUNTEROS : PUNTEROS A FUNCIONES : PARÁMETROS FUNCIONALES : GESTIÓN DE MEMORIA DINÁMICA:
29 29 29 30 30 30 31 31 32 33
6.- ARRAYS Y CADENAS
36
ARRAYS Y PUNTEROS : CADENAS DE CARACTERES : ARRAYS MULTIDIMENSIONALES : ARRAYS DE PUNTEROS : PARÁMETROS DEL PROGRAMA:
36 38 39 41 42
7.- ESTRUCTURAS
44
Manual de Lenguaje C
Pág. 1
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
CONCEPTO BÁSICO: DECLARACIÓN: INICIALIZACIÓN: OPERACIONES CON ESTRUCTURAS : PUNTEROS A ESTRUCTURAS : ESTRUCTURAS AUTORREFERENCIADAS : ESTRUCTURAS Y ARRAYS : UNIONES: CAMPOS DE BIT:
44 44 45 45 47 48 48 49 50
8.- ENTRADA Y SALIDA
52
CONCEPTOS : FICHEROS ESTÁNDAR: FUNCIONES DE ENTRADA Y SALIDA ESTÁNDAR: FUNCIONES DE ENTRADA Y SALIDA CON FORMATO : FUNCIONES DE ENTRADA Y SALIDA PARA CADENA DE CARACTERES : ACCESO A FICHEROS : TRATAMIENTO DE ERRORES :
52 52 53 53 57 57 61
Manual de Lenguaje C
Pág. 2
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
1.- INTRODUCCIÓN Características fundamentales
∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗
Creado por Dennis Ritchie en 1972. Basado en el lenguaje B de Thompson. Estrechamente asociado al sistema operativo UNIX. Lenguaje de nivel medio. Se aprende fácilmente. Eficiente. Lenguaje de propósito general. Portátil. Estructurado. Pocos tipos de datos.
Estructura de un programa C
∗ Programa en C formado por objetos externos: Variables externas, funciones externas. ∗ Definición de variables: especificación del nombre y el tipo de dato. ∗ Definición de una función: ⇒ Cabecera de la función, especifica el nombre, los parámetros y el tipo de dato que devuelve. ⇒ Cuerpo de la función, definición de variables internas y conjunto de sentencias ejecutables. ∗ Diferencia entre variables externas e internas: su ámbito y su existencia. Elementos sintácticos básicos
∗ Identificadores: Sirven para nombrar los elementos del programa. C hace distinción entre mayúsculas y minúsculas. ∗ Palabras clave: Palabras originales del lenguaje C. ∗ Constantes y cadenas: Tipos de datos predefinidos. ∗ Operadores: Operaciones a realizar sobre los datos. ∗ Separadores: Sirven para delimitar los símbolos del lenguaje. ⇒ Comentarios /* y */ Manual de Lenguaje C
Pág. 3
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
⇒ Delimitadores de bloque { y } ⇒ Terminadores de sentencia ; ⇒ Definición de función y declaración de parámetros ( y ) ⇒ Separación de parámetros y de las variables definidas en la misma declaración , Estilo de programación
∗ Objetivo hacer más claros los programas. ∗ Se potencia el uso de los comentarios. ∗ Se escribirá una sola sentencia en cada línea. Se producirá un sangrado en el texto por cada bloque.
Manual de Lenguaje C
Pág. 4
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIร N
COMENTARIOS
Manual de Lenguaje C
Pรกg. 5
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
2.- TIPOS DE DATOS Y OPERADORES Tipos de datos:
Existen cinco tipos básico de datos , que son: * char: Sirve para almacenar el juego de caracteres del código ASCI, rango de -127 a 127, tamaño aproximado 1 byte. * int: Representa números enteros con signo, rango de 32.767 a 32.767, tamaño aproximado 2 bytes. * float: Representa números reales en coma flotante, precisión simple ( 6 dígitos ), rango 3,4 E -107 a 3,4 E 107, tamaño aproximado 4 bytes. * double: Representa números reales en coma flotante, doble precisión ( 10 dígitos ), rango 1,7 E -308 a 1,7 E 308, tamaño aproximado 8 bytes. ∗ void: O bien declara explicitamente una función o bien no devuelve valor alguno, o crea punteros genéricos. Todo esto se tratará posteriormente. Modificadores al tipo básico * short ( int ): Usa menos espacio que un entero, rango 32.767 a 32.767. * long ( int ): Usa menos espacio que un entero, rango 2.147.483.647 a 2.147.483.647, tamaño 4 bytes. * unsigned ( int ): Representa enteros sin signo, rango 0 a 65.535. * unsigned short: Rango de 0 a 65.535. * unsigned long: Rango de 0 a 4.294.967.295. * unsigned ( char ): Rango de 0 a 255. * long float: Sirve para representar números reales con doble precisión ( double ). * long double: Tamaño 16 bytes con 10 dígitos de precisión. Variables:
Región de memoria que puede almacenar cualquier valor entre un conjunto de valores, los cuales dependen del tipo de variable.
Manual de Lenguaje C
Pág. 6
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
∗ Declaración: Se especifica el nombre, el tipo de la variable y el modo de almacenamiento, no reserva necesariamente memoria para la variable. modo_almacenamiento tipo_variable nombre_variable ∗ Definición: Se especifica el nombre y el tipo de la variable, reserva memoria para ella. ∗ Modos de almacenamiento: Especifica la forma en que debe almacenarse la variable. ⇒extern: Debe haber una y solo una definición de cada variable externa entre todos los ficheros que constituyen el programa, el resto de los ficheros pueden acceder a ella mediante declaraciones con modo de almacenamiento extern. Prob1.c Prob2.c int i=10; extern int i; ⇒static: Las variables declaradas de esta forma son locales al fichero en que se declaran, no pueden acceder el resto de los ficheros que constituyen el programa. Prob1.c Prob2.c Prob3.c static int i=9; int i=0; extern int i; La variable i local de Prob1.c no es la misma variable que la externa y a la que se refieren Prob2.c y Prob3.c ⇒auto: Se definen obligatoriamente dentro de un bloque, se crea cada vez que se entra dentro del bloque y desaparece cuando sale del mismo, sólo es accesible en el interior del bloque en que se declara. ⇒register: La variable se toma como auto pero puede almacenarse en los registros de computador, en lugar de en la memoria. ∗ Modos de acceso: Sirve para controlar el modo en que se accede a las variables. ⇒const: Las variables declaradas de esta forma no pueden ser modificadas explícitamente durante la ejecución del programa.
Manual de Lenguaje C
Pág. 7
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
⇒volatile: Indica al compilador que el valor de una variable puede cambiarse por medios no especificados explícitamente en el programa. ∗ Inicialización: Sirve para dar un valor inicial a las variables, se puede inicializar una variable a la vez que se declara. ⇒Las variables globales y static sólo son inicializadas al principio del programa, se inicializan a cero si no se especifica lo contrario. ⇒Las variables locales y register se inicializan cada vez que se entra en la función, si no se inicializan adoptan valores desconocidos. Constantes:
Se refieren a valores fijos que no pueden alterarse durante la ejecución del programa. ∗ Definición: Mediante la palabra reservada #define nombre de la constante valor de la constante. ∗ Tipos de constantes: Entera, Carácter, Reales Cadenas => Entera: Formada por una secuencia de dígitos que representan un valor entero con signo. u decimal: El primer dígito debe ser distinto de cero. u octal: El primer dígito debe ser cero y los demás comprendidos entre 0 y 7. u hexadecimales: comienzan por =x, y el resto deben ser dígitos entre 0 y 9, y desde la A a la F. => Carácter: Es un único carácter encerrado entre apóstrofes. u especiales: Formados por los apóstrofes, la barra invertida y un carácter. `\b` Retroceso `\n` Salto de línea `\r` Salto de carro `\t` Tabulador horizontal `\0` Valor nulo Manual de Lenguaje C
Pág. 8
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
=> Reales: Consisten en una parte entera, un punto, una parte fraccionaria. => Cadenas de caracteres: Secuencia de caracteres encerrados entre comillas. Operadores:
Son operaciones que se realizan sobre diferentes tipos de datos, son los siguientes: * Aritméticos: Son los binarios, representados por +,-,*,/,% este último sólo se puede emplear con tipos de datos enteros. * Cambio de signo: Es unario se representa mediante el símbolo -. * Relacionales: Operadores binarios, son: >, <, >=, <=, ==, !=. * Lógicos: Binarios, son && (y lógico), || (o lógico). Unario es el operador de negación !. * Manejo de bits:Son en general operadores binarios, son & AND bit a bit se usa a menudo para poner a = un cierto conjunto de bits, | OR bit a bit se suele usar para poner a 1 un cierto conjunto de bits, ^ Or exclusivo bit a bit, << desplazamiento a la izquierda se añade 0s por la derecha, >> desplazamiento por la derecha se añade 0s por la izquierda, y el único operador unario es ~ complemento a uno. * Asignación: Todos son binarios y son los siguientes =,+=,=,>>0,<<=,/=,*=,&=,/=,|=, ^=. * Incremento y decremento: Operadores unarios sirven para incrementar o decrementar variables de cualquier tipo básico, que son ++ incremento - decremento, se pueden poner como prefijo ++n o como sufijo n++, los efectos son diferentes. ∗ Expresiones condicionales: C dispone de un operador ternario para evaluar alternativas, formando una expresión condicional como la siguiente: expre1 ? expre2: expre3 Se evalúa la primera expresión, y si es distinto de 0 , el resultado de la expresión condicional es el de la segunda expresión; si es falsa el resultado es de la tercera expresión.
Manual de Lenguaje C
Pág. 9
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
Ej) (a>b) ? i=a: i=b ;
<=> if (a<b) i=a; else i=b;
Tabla de jerarquías y orden de evaluación. Precedencia Orden de evaluación (),[],-> I-D -, !, ~, ++ , --, (tipo), *, D-I & *, /, % I-D +, I-D >>, << I-D <, <= ,> ,>= I-D = =, != I-D & I-D ^ I-D | I-D && I-D || I-D ?: D-I =, +=, -=. etc... D-I Conversión de tipo:
Cuando en una expresión se mezclan operandos de diferentes tipos, se realiza una conversión de los tipos operación a operación, siguiendo las siguientes reglas: * Aritméticas: Si un operador tiene dos operandos de tipo diferente, el de inferior se convierte al tipo superior antes de efectuar la operación. * Asignación: El valor de la expresión de la parte de la derecha de la asignación se convierte al tipo de la variable de
Manual de Lenguaje C
Pág. 10
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
la parte izquierda, y éste es el tipo del resultado de la expresión de asignación. * Explícitas: Se fuerzan conversiones explícitas de tipo en cualquier expresión mediante el operador de moldeado (cast). * Parámetros de funciones: Los parámetros actuales en las llamadas a las funciones también son expresiones, y por lo tanto, también se les aplican las reglas de conversión de tipos anteriores. Tipos enumerados:
En ANSI C es posible declarar una lista de constantes enteras con nombre mediante la declaración de un tipo enumerado. Sintaxis: enum nombre_enumerado { lista de constantes} ; donde el nombre especifica el nombre del tipo enumerado, y es opcional. Ej) enum colores { amarillo, rojo, verde, azul}; El compilador asigna valores enteros consecutivos a las constantes comenzando por 0. Sin embargo, se pueden asignar valores arbitrarios a las constantes, especificándolo explícitamente. Ej) enum colores { amarillo, rojo =4, verde, azul }; /* verde toma el valor 5 y azul el 6 */ Definición de tipos:
Cuando una declaración de variables le precede la palabra typedef, entonces los identificadores especificados en la declaración no se refieren a variables, sino a nombres de tipo que se corresponden con el tipo descrito en la declaración. Ej) typedef int entero; /* entero <=> int */
Manual de Lenguaje C
Pág. 11
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIร N
A partir de ahora una variable se puede declarar mediante el tipo entero, es decir, se puede especificar entero var ; typedef enum colores{ amarillo, rojo, verde, azul } COLOR; /* donde COLOR no es el nombre de la variable sino el nombre del tipo enumerado colores */
Manual de Lenguaje C
Pรกg. 12
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIร N
COMENTARIOS
Manual de Lenguaje C
Pรกg. 13
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
3.- CONTROL DE FLUJO Expresiones y sentencias: ∗ ∗ ∗
Expresión: Es una combinación de operadores y operandos. Sentencia simple: Es una expresión seguida de un punto y coma Sentencia compuesta: Son un conjunto de declaraciones y sentencias encerradas entre llaves{}.
Sentencias de control de flujo:
Son aquellas que modifican la ejecución secuencial de las sentencias que forman el programa. ∗ Sentencias condicionales: Permiten la ejecución selectiva de un conjunto de sentencias, dependiendo de unas ciertas condiciones. ⇒ if - else: sintaxis if (expresión) sentencia 1; else sentencia 2; En caso de sentencias completas: sintaxis if(condición 1) { sentencia 1; sentencia 2; } else { sentencia 3; sentencia 4; } ⇒ switch: es una alternativa a los if anidados para realizar decisiones múltiples. Sintaxis switch( expresión) { case expr_constante 1: lista sentencias;
Manual de Lenguaje C
Pág. 14
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
case expr_constante 2: lista sentencias; case expr_constante 3: lista sentencias; default: lista de sentencias; } ∗ Sentencias repetitivas: Permiten repetir la ejecución de un conjunto de sentencias mientras que se cumpla cierta condición. ⇒ while: Se ejecuta repetidamente las sentencias si el valor de la expresión es distinto de cero. Sintaxis while (expresión) { sentencia 1; sentencia 2; } ⇒ do _ while: Se ejecutan las sentencias como minimo una vez. Sintaxis do { sentencia 1; sentencia 2; } while (expresión); ⇒ for: sintaxis for ( expresión1 ; expresión 2; expresión 3) { sentencia 1; sentencia 2; } expresion1: especifica la inicialización del bucle expresión 2: especifica una comprobación que se realiza antes de cada iteración, de manera que se abandona el bucle cuando la expresión valga cero expresión 3: especifica las acciones a realizar al final de cada iteración.
Manual de Lenguaje C
Pág. 15
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
Todas la expresiones son opcionales, pero deben mantenerse los puntos y comas. ∗ Sentencias de salto: Permiten alterar de manera incondicional el orden de ejecución de las sentencias del programa. ⇒ break: Provoca la finalización de la sentencia while, do -while, for, o switch más interna que contenga la sentencia break. ⇒ continue: Transfiere el control al final del bucle while, do - while, o for , con el objeto de comenzar una nueva iteración. ⇒ goto: El control del bucle puede alterarse incondicionalmente usando la sentencia goto. Sintaxis goto identificador; …………………. …………………. Identificado: sentencia ; ⇒ return: devuelve el control desde el interior de una función a la siguiente sentencia a la llamada a esa función. Puede ser return ; en cuyo caso, el valor devuelto por la función queda indefinido, o bien: return expresión ; donde la función devuelve el valor de la expresión especificada.
Manual de Lenguaje C
Pág. 16
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIร N
COMENTARIOS
Manual de Lenguaje C
Pรกg. 17
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
4.- FUNCIONES Conceptos básicos:
Un programa en C está formado por un conjunto de objetos, que son las variables y las funciones. ∗ Concepto de función: Una función en C es una porción de código ejecutable que devuelve un valor al ser invocada. Todas las funciones son externas, es decir, no se permite la definición de funciones en el interior de otras funciones. Definición:
La sintaxis es la siguiente: modo tipo nombre de la función (lista de parámetros) declaración de parámetros bloque o cuerpo ∗ El tipo especifica el tipo del valor devuelto por la función, mientras que el nombre de la función debe ser un identificador que se usará para invocarla. Si no se especifica el tipo, se considera de tipo entero. Si el tipo es void indica que la función no devuelve ningún valor. ∗ El bloque o cuerpo de la función especifica el conjunto de sentencias que se ejecutan al invocar a la función, así como el conjunto de declaraciones y definiciones internas a esa función. ∗ El modo puede ser extern o static. Si el modo es extern, la función puede ser usada en todos los ficheros que forman el programa. Si el modo es static , la función sólo puede ser usada en el fichero en el que se encuentra la definición; puede haber distintas definiciones estáticas con el mismo nombre en los diferentes ficheros del programa. Declaracíon:
Para poder hacer referencia a una función en un fichero antes de su definición o en otro fichero distinto al que incluye su Manual de Lenguaje C
Pág. 18
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
definición, es necesario realizar una declaración anticipada de esa función. ∗ La sintaxis es la siguiente: modo tipo nombre de la función () ⇒La declaración de la función no define la función, es decir, no especifica el conjunto de declaraciones y sentencias que componen el cuerpo de la función. ⇒Si se omite el tipo, se considera de tipo entero. ⇒El modo puede ser extern o static. Si no se especifica modo se considera que es extern. Si se especifica la función con modo extern, se declara la función para su uso en el ámbito de la declaración; la definición debe encontrarse en alguno de los ficheros que forman el programa. Ej. 1) extern int f(); /* declaración de f() */ int g() /* definición de g() */ { ………. f(); /* llamada a f() */ } int f() /* definición de f() */ { ……. } EJ. 2 ) p1.c p2.c int f() extern int f() { …… int g() ……. { } ……. f(); } se refieren a la misma función. ⇒Si el modo es static, se declara la función para ser referenciada sólo en ese fichero, sin embargo, no
Manual de Lenguaje C
Pág. 19
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
puede ser invocada desde otros fichero del programa. La definición de la función debe encontrase en el mismo fichero. Ej. 1) p1.c p2.c p3.c static int f(); extern int f(); int f() { int g() int h() ……. { { ……. …….. f(); } f(); ……. } } static int f() Si son la misma { ……. } No son la misma Prototipos de funciones:
En un C original, en la declaración de una función no hace referencia ni al número ni al tipo de sus parámetros. Prototipar una función es especificar el tipo y el número de sus parámetros. ∗ Los prototipos de las funciones permiten realizar la comprobación del número y tipo de los parámetros actuales que se usan en la llamada a las funciones, frente al número y tipo de los parámetros formales de las mismas, informando de cualquier diferencia. ∗ La sintaxis del prototipo de una función es: modo tipo nombre(tipo1 param1, tipo2 param2,.tipo n param n) donde los nombre de los parámetros son opcionales Si el prototipo de una función es de tipo void indica que dicha función no tiene parámetros de entrada.
Manual de Lenguaje C
Pág. 20
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
Parámetros de una función:
Se corresponden con una serie de valores que se especifican en la llamada a la función, de los que dependen el resultado de la función. ∗ Los parámetros o argumentos de una función se pueden clasificar en: ⇒Formales: Se usan en la definición de la función. Las sentencias y declaraciones que componen el cuerpo de la función usan estos parámetros como cualquier otra variable interna a ese cuerpo. ⇒Actuales: Se usan en la llamada a la función. Son valores que se copian en los parámetros formales especificados en la definición. En C, todos los parámetros se pasan “por valor”, es decir, en cada llamada a la función se genera una copia de los valores de los parámetros actuales, que se almacenan en variables temporales en la pila mientras dure la ejecución de la función. Sin embargo, cuando sea preciso, es posible hacer que una función modifique el valor de una variable que se pase como parámetro actual en la llamada a la función. Para ello, lo que se debe proporcionar a la función no es el valor de la variable, sino su dirección, lo cual se realiza mediante un puntero que apunte a esa dirección. Recursión:
Cuando durante la ejecución de una función se realiza una invocación a esa misma función se dice que se produce una llamada recursiva a esa función. ∗ La recursión puede ser de dos tipos: ⇒ Propia: La función se invoca explícitamente a así misma. ⇒ Mutua: La función llama a otra función, que directa o indirectamente llama a la primera. Las codificaciones no recursivas son, en general, más eficientes en términos de espacio de almacenamiento t
Manual de Lenguaje C
Pág. 21
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
tiempo de ejecución que las recursivas, debido a que cada vez que se invoca a la función se crea un nuevo juego de variables automáticas y de copias de los parámetros actuales. Sin embargo, en muchos casos, el modo más natural de describir un proceso es mediante una formulación recursiva, de modo que expresar ese proceso en una formulación equivalente no recursiva puede ser muy complicado. El prepocesador de C:
En un código fuente de C se pueden incluir una serie de instrucciones que no pertenecen al lenguaje en sí, y que facilitan el desarrollo de los programas. Estas instrucciones se denominan directivas o líneas de control del compilador, y se procesan durante la compilación del programa por el llamado preprocesador de C, que se ejecutan antes del proceso de compilación propiamente dicho. ∗ La sintaxis de las líneas de control es: # directiva contenido ⇒ Símbolo #: indica que se trata de una directiva ⇒ Directiva: indica los tipos de instrucciones que puede soportar el preprocesador. ⇒ Contenido: indica lo que debe hacer cuando se precompile. Su sintaxis es independiente de la del resto del lenguaje de C. No llevan punto y coma para terminar la sentencia, y van al principio del fichero. ∗ Tipos de directivas: ⇒ Sustitución de macros: Una macro es un texto que se incluye en el fichero fuente de un programa durante su compilación. El texto a insertar puede depender de ciertos parámetros de la macro. Posibles ventajas: ♦ Son más rápidas que las llamadas a funciones
Manual de Lenguaje C
Pág. 22
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
♦ Si los parámetros se manejan correctamente, sirven para cualquier tipo de datos. ♦ Es posible pasar nombre de tipos como parámetros de la macro. Posibles desventajas: ♦ Ocupan más espacio que las funciones, puesto que una misma macro se puede insertar varias veces en el código. ♦ Su sintaxis es más delicada que la de las funciones. Distintos tipos de macros: ♦ Macros sin parámetros: sintaxis: # define identificador cadena Puede haber varios blancos entre el identificador y la cadena, pero una vez comience la cadena, ésta sólo termina con un salto de línea. Provoca que el preprocesador sustituya las siguientes apariciones del identificador durante la compilación del resto del programa por la cadena de caracteres que se especifica. A esto de denomina sustitución de la macro. Si la cadena no cabe en una única línea puede continuar en la siguiente, escribiendo la barra invertida \ al final de la línea. Ej ) # define MAX 20 # define MENSAJE “ Hola \ como estas “ ♦ Macros con parámetros sintaxis: # define identificador(id1,…idn) cadena No puede haber ningún espacio entre el identificador y el ( .
Manual de Lenguaje C
Pág. 23
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
Cada parámetro formal especificado en la definición se sustituye por el correspondiente parámetro actual en la llamada a la macro. El número de parámetros formales y actuales deben coincidir. Los parámetros actuales se separan en la llamada a la macro mediante comas, que no pueden estar entre comillas o paréntesis. Ej) # define MULT(a,b) a*b /* definición */ x= MULT(5+3,8); /* llamada */ ♦ Eliminación de macros Provoca que el identificador deje de estar definido para el preprocesador. Sintaxis: # undef identificador Ej) # define N 3 int i = N; # undef N ⇒ Inclusión de ficheros: Provoca que el compilador pase a compilar el fichero cuyo nombre se especifica. Cuando finalice la compilación de ese fichero se continua con la siguiente línea del fichero actual. Sintaxis: # include “nombre del fichero “ # include <nombre del fichero> Si el nombre del fichero se especifica entre comillas, se busca el fichero en un determinado directorio, normalmente en el directorio actual, y si no se encuentra en ese directorio, lo busca en un directorio predefinido, normalmente el directorio include. Si se especifica el nombre del fichero entre < y >, entonces el fichero se busca directamente en el directorio predefinido. Ej )
Manual de Lenguaje C
Pág. 24
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
p.h extern int i; extern int f(); p.c # include “p.h” int i=0;
q.c # include “p.h” …………… i…..; f(); ………..
int f() { …….. ……. } ⇒ Compilación condicional: Indica si se van a compilar un conjunto de sentencias o no. Pueden existir diferentes tipos de sentencias de compilación condicional. Sintaxis: # if expresión_constante lista_sentencias # endif Si la expresión constante es cierta (distinta de cero), se compila la lista de sentencias. Si es falsa no se compilan. Ej) # define DEPURAR int mult( int a, int b) { # if DEPURAR printf(“ el resultado es %d”, a*b); #endif return a*b; } # if expresión_constante lista_sentencias1
Manual de Lenguaje C
Pág. 25
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
# else lista_sentencias2 # endif Si la expresión constante es cierta, se compila la lista de sentencias1. Si es falsa se compila la lista se sentencias2. Ej) #define P 1 # if P= = 1 int mult (int a, int b) # else int mult( a, b) int a,b; # endif { return a*b; } # ifdef identificador lista_sentencias # endif Si el identificador está definido previamente para el preprocesador (mediante # define), se compilan las sentencias, si no está definido no se compilan. # ifndef identificador lista_sentencias # endif Si el identificador no está definido previamente para el preprocesador (mediante # define), se compilan las sentencias, si está definido no se compilan. Ambas directivas pueden usar # else. # if expresión_constante1 lista_sentencias1 # elif expresión_constante2 lista_sentencias2 # elif expresión_constante3 .................. # elif expresión_constanteN Manual de Lenguaje C
Pág. 26
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
lista_sentenciasN # else lista_sentencias # endif Se evalúan las expresiones constantes en el orden en que aparecen. Cuando una expresión sea cierta se compilan las sentencias correspondientes y se sigue compilando la siguiente línea tras #endif. Si no se cumple ninguna expresión y existe # else, se compila las sentencias correspondientes.
Manual de Lenguaje C
Pág. 27
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIร N
COMENTARIOS
Manual de Lenguaje C
Pรกg. 28
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
5.- PUNTEROS Punteros y direcciones:
Un puntero es una variable que contiene la dirección de memoria en la que se almacena otra variable de un cierto tipo. Si p es un puntero que contiene la dirección de memoria de una variable x, se dice que p apunta a x. Declaración de punteros:
Deben declararse antes de usarse como una variable cualquiera. Sintaxis: modo tipo * identificador = expresión ; Declaración de una variable puntero que apunta a variables del tipo que se especifica, y que se inicializa al valor de la expresión. Si la expresión especificada es la constante 0 o la macro NULL, definida en <stdlib.h>, significa que el puntero no apunta a ninguna variable. Operadores de punteros:
Hay dos operadores unarios que se usan para manejar punteros, estos son: ∗ Operador &: Es el operador que devuelve la dirección de memoria de su operando, que debe ser obligatoriamente una referencia a una zona de almacenamiento. ∗ Operador *: Que permite acceder a la variable situada en la dirección de memoria especificada en el operando Ej) int i=5, *p ; p=&i; /* asignamos la dirección de la variable i */ *p =10; /* cambiamos el contenido de la variable */
Manual de Lenguaje C
Pág. 29
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
Comparación de punteros:
Se pueden relacionales. Ej)
comparar
punteros
mediante
los
operandos
int * p ,* q; p = = q /* es cierto si p y q apuntan a la misma variable */ *p = = *q /* es cierto si las variables a las que apuntan p por un lado, y q por el otro, tienen el mismo valor */ p<q /* es cierto si p apunta a una variable situada en memoria antes de la variable apuntada por q */ p<*q /* es cierto si la variable a la que apunta p es mayor que la variable a la que apunta q */ Asignación de punteros:
Es posible asignar el valor de un puntero a otra variable puntero. Ej) int * p, * q; p=q /* p apunta a la misma variable que q */ *p = *q /* la variable apuntada por p toma el valor de la variable apuntada por q */ Punteros como parámetro de funciones:
Los parámetros de las funciones se pasan por valor, por lo que no es posible alterar directamente el valor de un parámetro actual desde el interior de una función. Para modificar el valor de un parámetro actual es necesario pasar su dirección y no su valor. Ej) inter (int * pi, int * pj) { int temp; temp = * pi ; *pi = *pj; *pj = temp; return 0; } Manual de Lenguaje C
Pág. 30
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
main() { int i =3, j=5; inter( &i, &j); return 0; } Aritmética de punteros:
Si p y q son punteros de un cierto tipo, entonces: p+n /* es la dirección del enésimo objeto situado tras el objeto al que apunta p */ p-n /* es la dirección del enésimo objeto situado antes del objeto al que apunta p */ p-q /* es el número de objetos situados entre p y q */ Los operadores de incremento y decremento también son aplicables a variables puntero de cualquier tipo. p++ /* evalúa a p, y p apunta al siguiente objeto */ ++p /* evalúa a p+1, y p apunta al siguiente objeto */ Estas operaciones aritméticas sólo tienen sentido cuando p y q son punteros a elementos de un mismo array. En otro caso, los resultados pueden variar de una implementación a otra. Punteros a funciones:
En C es posible definir punteros a funciones, que contienen la dirección de memoria en la que se encuentra una función. ∗ Declaración de punteros a funciones: La sintaxis de la definición es: modo tipo (* iden_punt) ( ) ; donde iden_punt es un puntero a una función de un cierto tipo Ej) int (*pf) () ; /* pf es un puntero a una función que devuelve un entero */ int ( *pf) ( int, int) /* pf es un puntero a una función que devuelve un entero a partir de dos enteros */
Manual de Lenguaje C
Pág. 31
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
∗ Asignación de punteros a funciones: El nombre de la función indica la dirección de memoria donde esta almacenada en memoria. Sintaxis: pf = nombre_función /* no hace falta el operador & */ ∗ Invocación de funciones mediante punteros: Sintaxis de como se puede llamar a una función mediante un puntero a dicha función: ( * pf) (lista de parámetros actuales) ; Ej) void escribir(int x) { printf(“% d\n”, x); } main() { int ( *pf) (int) ; pf = escribir ; (*pf ) (4); return 0; } Parámetros funcionales:
Una utilidad de los punteros a funciones es que permite pasar funciones como parámetros en la llamada a otras funciones. Ej) int suma ( int i, int j) { return i+j; } int mult ( int i, int j) { return i*j;
Manual de Lenguaje C
Pág. 32
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
} int generica ( int i, int j, int (*pf) (int, int)) { return (*pf) (i,j); } main( ) { printf(“% d \ n” , generica( 3,4,suma)) ; printf(“% d \ n” , generica( 4,5,mult)) ; return 0; } Gestión de memoria dinámica:
Son un conjunto de funciones predefinidas , las cuales permiten generar y gestionar memoria dinámica, estas son: ∗ char alloc (int tamaño): Reserva una zona de memoria dinámica del tamaño que se pasa como parámetro. Devuelve la dirección de la zona de memoria creada, o NULL si no se puede crea esa zona. ∗ char calloc ( int nobjs, int tamaño): Reserva una zona de memoria dinámica para albergar nobjs objetos de ese tamaño. Devuelve la dirección de la zona de memoria creada, o NULL si no se puede crear esa zona. La zona de memoria creada se inicializa con ceros. ∗ int free (char *p): Libera una zona de memoria dinámica apuntada por el puntero p. p debe ser una dirección obtenida mediante una llamada a alloc ( ). ∗ int cfree(char *p): Libera una zona de memoria dinámica apuntada por el puntero p. p debe ser una dirección obtenida mediante una llamada a calloc ( ). Todas estas funciones se encuentran predefinidas en el fichero # include <stdio.h> ∗ void malloc (size_t tamaño): Igual que alloc ( ). ∗ void calloc(size_t nobs, size_t tamaño): Igual que calloc(). ∗ void free( void * p): Libera memoria tanto para los punteros obtenidos con malloc() como con calloc(). Manual de Lenguaje C
Pág. 33
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIร N
Todas estas funciones se encuentran predefinidas en el fichero # include <stdlib.h>
Manual de Lenguaje C
Pรกg. 34
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIร N
COMENTARIOS
Manual de Lenguaje C
Pรกg. 35
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
6.- ARRAYS Y CADENAS Arrays y punteros:
Un array es una estructura de datos formada por un número fijo de elementos de un cierto tipo que se almacenan en posiciones consecutivas de la memoria. ∗ Declaración: La sintaxis de la declaración de un array es: modo tipo nombre_array [ dimensión ] La dimensión debe ser una expresión entera constante, y mayor que 0. Es posible omitir la dimensión del array, en cuyo caso el array tiene tipo incompleto. En este caso, es posible completar el tipo del array mediante su inicialización. Ej) int a[10]; /* Array de 10 enteros */ ∗ Acceso a los elementos de un array: Para acceder a un elemento de un array se escribe el nombre del array, seguido del valor de su índice encerrado por el operador [ ]. Ej ) a[2] /* tercer elemento del array a */ ∗ Inicialización de arrays: Es posible inicializar un array de elementos de un cierto tipo durante su definición, mediante una secuencia de expresiones separadas por comas, y encerradas entre llaves. El orden de las expresiones coincide con el orden de los elementos del array, de manera que la primera expresión corresponde al valor inicial del primer elemento del array, y así sucesivamente. EJ) int a[10]= {0,1,2,3,4,5,6,7,8,9}; int a[ ] = {0,1,2,3,4,5,6,7,8,9}; ∗ Arrays constantes: Si un array se declara como const, trata de modificar el valor de un elemento del array provoca un error de compilación. EJ) const int a [10] = { 1,2,3,4,5,6,7,8,9,1};
Manual de Lenguaje C
Pág. 36
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
a[6] = 23; /* Error */ ∗ Semejanza y diferencias entre arrays y punteros: Cuando en una expresión se especifica el nombre de un array, lo que realmente se evalúa es la dirección de su primer elemento. Por tanto, esta dirección puede almacenarse en un puntero a los elementos del array. EJ) int a[10]; int * p; p = a; a ó &a[0] ó p /* Todas estas expresiones indican la dirección del primer elemento del array */ a[0] ó p[0] ó *a ó *p /* Todas estas expresiones indican el contenido del primer elemento del array */ a + n ó &a[n] /* Indica la dirección del enésimo elemento del array */ *(a+n) ó a[n] /* Se accede al elemento enésimo del array */ La diferencia fundamental entre un puntero y el nombre de un array es que, mientras que un puntero es una variable cuyo valor puede modificarse, el nombre de un array es una dirección constante que no puede ser alterada. ∗ Arrays como parámetros de funciones: Cuando un array se pasa como parámetro actual en la llamada a una función lo que se pasa realmente es una copia de la dirección de su primer elemento, que como se ha comentado es una constante. Sin embargo, el valor de la copia si se puede modificar en el interior de la función. Por tanto los arrays se pasan por referencia no por valor. ∗ Asignación de arrays: Como se ha comentado, cuando se referencia un array lo que se evalúa es la dirección de su primer elemento. Esta dirección es constante y no puede modificarse. Por lo tanto, para copiar un array en otro no se puede usar una única sentencia de asignación. EJ) int a[10];
Manual de Lenguaje C
Pág. 37
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
int b[10]; b = a; /* Error, ya que b es una dirección constante */ Para copiar un array en otro, se debe copiar elemento a elemento. ∗ Comparación de arrays:Por la misma razón expuesta en el apartado anterior, no es posible comparar arrays mediante el operador de igualdad. EJ) int a[]= { 1,2,3,4,5,6}; int b[] = { 1,2,3,4,5,6} ; b = a; /* Es siempre falso, pues se comparan sus direcciones */ Para comparar dos arrays, deberemos comparar elemento a elemento. Cadenas de caracteres:
Las cadenas de caracteres o strings se tratan en C como arrays de caracteres, en las que al final de la cadena se estipula mediante el carácter nulo ´\0`. Por tanto, para las cadenas de caracteres rigen todas las reglas aplicables a los arrays en general. ∗ Cadenas constantes: Es una secuencia de caracteres encerrados entre comillas dobles. Cuando el compilador encuentra una cadena constante formando parte de una expresión, reserva una zona en la memoria de datos para almacenar consecutivamente los caracteres de la cadena, y añade automáticamente el carácter nulo ´\0`al final. Por tanto, un puntero a un carácter puede asignarse para apuntar a una cadena constante. EJ) char a[]= “hola estoy bien “; /* Un array de cadenas de caracteres */ char * p = “adios hasta luego “; /* Una cadena constante */ Las diferencias esenciales entre los arrays de caracteres y las cadenas constantes son: la primera es que las cadenas constantes son anónimas, mientras que los
Manual de Lenguaje C
Pág. 38
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
arrays de caracteres pueden nombrarse mediante su identificador; la segunda. Que está indefinido el resultado de modificar el contenido de una cadena constante. La diferencia entre un puntero a una cadena constante y un array de caracteres, es en primer lugar que la variable puntero que contiene la dirección donde el compilador almacena la cadena constante, puede cambiarse para apuntar a otro carácter, e incluso modificarlo; por otro lado la variable array en la que se almacena la cadena no puede modificarse, pero si pueden modificarse sus caracteres. ∗ Librería de gestión de cadenas de caracteres: Las funciones que gestionan las cadenas de caracteres se encuentran en el fichero <string.h>. Algunas de estas funciones son: size_t strlen ( const char * ). Devuelve el número de caracteres de la cadena sin contar el carácter nulo. char * strcpy ( char *, const char *) . Copia la segunda cadena en la primera cadena, incluyendo el carácter nulo. Debe haber suficiente espacio en la primera cadena para albergar todos los caracteres de la segunda cadena. Devuelve la dirección de la primera cadena. int strcmp ( const char *, const char *). Compara dos cadenas. Devuelve un valor menor que 0 si la primera cadena es menor que la segunda cadena, 0 si son iguales, o un valor mayor que 0 si la primera cadena es mayor que la segunda. Arrays multidimensionales:
Se consideran como arrays cuyos elementos son a su vez arrays. ∗ Declaración de arrays multidimensionales: Tiene la siguiente sintaxis modo tipo
Manual de Lenguaje C
nombre_array [dimen1]……[dimenn];
Pág. 39
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
Las dimensiones deben ser expresiones enteras, y mayores que 0. Sólo se permite omitir la primera dimensión del array, en cuyo caso el array tiene tipo incompleto. En este caso, es posible completar el tipo del array mediante su inicialización. Ej) int a[3][5]; /* Array de 3 subarrays de 5 enteros */ int a[][4]; /* Array de subrrays de 4 enteros */ ∗ Acceso a los elementos de una array multidemensional: para acceder a un elemento de un array multidemensional se escribe el nombre del array, seguido del valor de los índices correspondientes encerrados por el operador []. Ej) a[1][0] /* Primer elemento del segundo subarray del array a */ ∗ Inicialización de arrays multidimensionales: Es posible inicializar un array multidimensional de elemento de un cierto tipo durante su definición, mediante una secuencia se expresiones separadas por comas, y encerradas entre llaves. Ej) int a[2][3]= { {1,2,3}, {4,5,6} }; o bien: int a[2][3] = {1,2,3,4,5,6}; /*Menos claro */ ∗ Arrays multidimensionales y punteros a arrays: Cuando en una expresión se especifica el nombre de un array, lo que realmente se evalúa es la dirección de su primer elemento, que , en el caso de los arrays multidimensionales, es un array. EJ) int a[2][3];
Manual de Lenguaje C
Pág. 40
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
a ó &a[0] /* Dirección del subarray a[0] */ a + 1 ó &a[1] /* Dirección del subarray a[1] */ La dirección de los subarrays, que son constantes, puede almacenarse en una variable puntero a un array, cuya definición es: tipo (* nombre_puntero) [dimensión] ; Ej) int (*p)[3]; /* p es un puntero a un array de 3 enteros */ p= a; /* p apunta al subarray a[0] */ p= a + 1; /* p apunta al subarray a[1] */ También es posible acceder a uno de los subarrays, en cuyo caso se evalúa la dirección de su primer elemento. Ej) a[0] ó *a ó &a[0][0] ∗ Arrays multidimensionales como parámetros de funciones: Al igual que sucede con los arrays unidimensionales, cuando en la llamada a una función se pasa como parámetro el nombre de un array multidemensional lo que se pasa realmente es una copia de la dirección de su primer elemento que, en este caso, es un array. Sin embargo, el valor de la copia si puede ser modificada en el interior de la función. Arrays de punteros:
Un array de punteros es un array cuyos elementos son punteros a objetos (variables o funciones) de un cierto tipo. Sintaxis: modo tipo * nombre [dimensión] ; Ej) int * p[10]; /* Array de 10 punteros a enteros */ int (* p[10])(void) /* Array de 10 punteros a funciones de tipo entero sin parámetros */
Manual de Lenguaje C
Pág. 41
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
Parámetros del programa:
El lenguaje C permite transmitir parámetros al programa, que se suministran al invocarlo a través de la línea de comandos o mediante algún mecanismo dependiente del sistema. La función main() tiene dos parámetros opcionales: argc: Un entero que recibe el número de parámetros con los que se invoca el programa. Vale como mínimo 1. argv: Un array de punteros a char, que apuntan a cadenas de caracteres que contienen los parámetros del programa. Por convenio, argv[0] apunta a una cadena que contiene el nombre del programa en el sistema operativo.
Manual de Lenguaje C
Pág. 42
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIร N
COMENTARIOS
Manual de Lenguaje C
Pรกg. 43
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
7.- ESTRUCTURAS Concepto básico:
Una estructura es un tipo de datos que se compone de un conjunto de variables, llamados campos o atributos, que pueden ser de distintos tipos. Declaración:
La declaración de una estructura define un identificador para referirse a un tipo de datos. Por tanto, no reserva espacio para ninguna variable. struct iden_tipo { tipo1 campo1; tipo2 campo2; ……………… tipoN campoN; }; Los nombres de los campos pueden coincidir con los nombres de otras variables ordinarias y con el nombre de campos de otras estructuras. En la declaración de una estructura pueden declararse variables de ese tipo, siguiendo a la llave derecha. modo struct iden_tipo { tipo1 campo 1; ………………. } var1,….,varN; Ej) struct alumno{ */
/* alumno es un identificador de tipo
char nombre[20]; int edad;
Manual de Lenguaje C
Pág. 44
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
} pepe; /* pepe es una variable */ Posteriormente a la declaración de la estructura es posible declarar otras variables de ese tipo usando el identificador del tipo. Ej) struct alumno juan; Inicialización:
Se pueden inicializarse durante su definición usando una lista de expresiones constantes, separadas por comas, y encerradas entre llaves. El orden de las expresiones coincide con el orden de los campos en la declaración de su tipo. Ej) struct alumno pepe= { “ Jose Perez Gonzalez”, 23 }; Operaciones con estructuras:
Sólo se pueden realizar tres operaciones con las variables de tipo estructuras: Acceso a los campos de la estructura, Calcular su dirección mediante el operador &, Calcular su tamaño mediante la función sizeof(). ∗ Acceso a los campos: Para acceder a un campo de una estructura se escribe el nombre de la variable estructura seguido del operador • (punto) y del nombre del campo referenciado. Ej) pepe.nombre=”Angel Gomez Garía”; El operador • tiene la máxima precedencia, al igual que () y [], y se asocian de izquierda a derecha. Puesto que los campos de las estructuras no están necesariamente en posiciones contiguas de memoria, la comparación de estructuras debe hacerse siempre campo a campo. ∗ Cálculo del tamaño y cálculo de la dirección: Para asignar estructuras es necesario hacerlo campo a campo, o bien usar la función de librería memcpy Manual de Lenguaje C
Pág. 45
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
mencpy( & variable de estructura, & variable de estructura, sizeof(identificador de tipo estructura) ) mediante el operador & se calcula la dirección de la variable de la estructura y con sizeof() se calcula el tamaño que ocupa la variable de tipo estructura en memoria. memc py(& juan, &pepe, sizeof(struct alumno)); ∗ Otras operaciones: Además se permite el acceso a estructuras completas en las siguientes operaciones: ⇒ Asignación de estructuras ( no comparción) juan = pepe; ⇒ Paso de estructuras por valor a funciones. void imprimir( struct alumno var) { printf(“ % s % d”, var.nombre,var.edad); } main() { struct alumno v_pepe= { “pepe gomez”, 12}; imprimir(v_pepe); } ⇒ Funciones que devuelven estructuras. void imprimir( struct alumno var) { printf(“ % s % d”, var.nombre,var.edad); } struct alumno crear ( char nombre [10], int edad) { struct alumno otro; otro.nombre=nombre; otro.edad=edad; return(otro); } main() { struct alumno v_pepe; v_pepe= crear(“pepe gomez”,12);
Manual de Lenguaje C
Pág. 46
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
imprimir(v_pepe); } Punteros a estructuras:
Es posible definir variables y parámetros formales de tipo puntero a una estructura, de la manera habitual: Ej) struct alumno v_pepe; struct alumno * p_pepe = & v_pepe; Es posible acceder a los campos de una estructura mediante un puntero: (* p_pepe).edad=13; Los paréntesis son necesarios, puesto que el operador • de acceso a los campos tiene mayor precedencia que el operador *. Por ser tan común el acceso a los campos de las estructuras mediante punteros, se dispone de un operador especifico -> (operador flecha), formado por operador menos y el operador mayor, asociado a los punteros a estructuras. p_pepe->edad = 13; Puesto que en C los parámetros de las funciones se pasan siempre por valor, para modificar una estructura desde el interior de una función, será necesario pasar su dirección, por lo que el correspondiente parámetro formal será un puntero a la estructura. void imprimir( struct alumno * var) { printf(“ % s % d”, var->nombre,var->edad); } void crear ( struct alumno * p_var, char nombre [10], int edad) { p_var->nombre=nombre; p_var->edad=edad; } main() {
Manual de Lenguaje C
Pág. 47
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
struct alumno v_pepe; crear(& v_pepe, “pepe gomez”,12); imprimir(&v_pepe); } Estructuras autorreferenciadas:
Es cuando un campo de una estructura es un puntero a una variable del mismo tipo que la estructura que se declara. Las estructuras autorreferenciadas, junto con la gestión de memoria, son los métodos más adecuados para implementar estructuras de datos dinámicas. Ej) struct alumno { char nombre [20]; int edad ; struct alumno * sig; }; Estructuras y arrays:
Los arrays y las estructuras pueden combinarse entre sí para crear tipos de datos complejos, por ejemplo arrays de estructuras, y estructuras con campos arrays. Ej) struct alumno { char nombre [20]; int edad ; }; struct grupo{ struct alumno v_alumnos[30]; /* Array de estructuras */ int cuanto; }; También se pueden inicializar un array de estructuras, exactamente igual que los array normales, sólo se tiene que tener que los elementos del array son estructuras. struct alunmo v_alumnos[2]={ {“pepe”,12},
Manual de Lenguaje C
Pág. 48
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
{“juan”, 13} }; Se puede acceder a los elementos de un array de estructuras, combinado la forma de acceder a los arrays y a las estructuras. printf(“%s%d”,v_alumnos[0].nombre,v_alumnos[0].edad) ; UNIONES:
Las uniones son tipos de datos que pueden contener, en instantes diferentes, campos variantes de diferentes tipos, y por tanto, tamaños. Por tanto, permiten que varias variables compartan el mismo espacio de almacenamiento. El tamaño de una unión debe ser suficiente para albergar el campo más grande. ∗ Definición: La sintaxis de la unión es: union iden_tipo { tipo1 campo1; ……………… tipoN campoN; }; Ej) union varios{ int uno; float dos; } var; El uso es indéntico al de las estructuras, excepto que en su declaración se usa la palabra union en lugar de la palabra struct. Además, la inicialización de una unión sólo puede hacerse con un valor del tipo de su primer campo. union varios otra= { 2}; /* Debe ser de tipo entero */
Manual de Lenguaje C
Pág. 49
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
CAMPOS DE BIT:
Al definir los campos de las estructuras se pueden especificar el tamaño en bits de los campos de una estructura, si éstos tienen tipo int o unsigned int. Estos campos, llamados campos de bit, se empaquetan en bits contiguos en memoria, pero su gestión es en gran medida dependiente de cada implementación. Debido a este empaquetamiento, no se puede acceder a la dirección de un campo de bit me diante el operador &. El número de bits de un campo de bit debe estar comprendido entre 0 y el número de bits usados para almacenar las variables de tipo int en la implementación utilizada. Ej) struct v_byte{ int bit0:1; int bit1:1; ……….. int bit7:1; }; Se pueden especificar campos de bit sin nombre, en cuyo caso, ese campo sirve para incluir bits de relleno en la estructura, no pudiéndose almacenar datos en él. struct v_byte{ int bit0:1; int :5; /* 5 bits de relleno */ int bit7:1; };
Manual de Lenguaje C
Pág. 50
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIร N
COMENTARIOS
Manual de Lenguaje C
Pรกg. 51
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
8.- ENTRADA Y SALIDA Conceptos:
Las facilidades de entrada y salida no forman parte del lenguaje de C en sentido estricto, sino que se implementan mediante variables, funciones, macros, y tipos definidos en librerías dependientes del sistema. Para disponer de estas facilidades de entrada y salida estándar es necesario incluir en el fichero fuente del programa el fichero de cabecera stdio.h, que contiene las declaraciones necesarias para las funciones de entrada y salida. La entrada y salida en C se realiza a través de los flujos de datos. Un flujo de datos es una fuente o destino de datos que puede estar asociado a un fichero o a otro dispositivo. Los flujos de datos pueden clasificarse en dos grupos: ∗ Flujos de texto: Formado por una secuencia de líneas. Cada línea está formada por 0 o más caracteres. Las líneas se separan mediante el carácter ‘\n’. La representación de valores enteros o reales en un flujo de texto requiere la conversión de esos valores del formato interno de la máquina a una secuencia de caracteres. ∗ Flujo binarios: Formado por una secuencia de bytes que representan datos en el formato interno de la máquina. Por lo tanto no se realiza ninguna conversión. Un flujo de datos se asocia a un cierto fichero o a un dispositivo mediante la apertura del flujo, y se destruye esta asociación al cerrarlo. Para hacer referencia a ese fichero o dispositivo, se realiza mediante un identificador de tipo denominado FILE *. Ficheros estándar:
Cuando comienza la ejecución de un programa se dispone de tres ficheros de texto abiertos automáticamente, que pueden ser nombrados mediante los siguientes identificadores, cuya declaración se encuentra en el fichero <stdio.h>: stdin /* Entrada estándar */
Manual de Lenguaje C
Pág. 52
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
stdout stderr
/* Salida estándar */ /* Salida de errores estándar */
Funciones de entrada y salida estándar:
Incluidas en el fichero <stdio.h> ∗ int getchar (void): Lee un carácter de la entrada estándar. Devuelve el carácter leído o EOF si se trató de leer el carácter de fin de fichero. ∗ int putchar (int ): Escribe un carácter en la salida estándar. Devuelve el carácter escrito o EOF si hay algún error. Incluidas en el fichero <conio.h>, no son sentencias de ANSI C. ∗ int getch (void): Lee carácter de la consola sin eco. Previamente, descarta cualquier dato almacenado en el buffer de entrada. ∗ int getche (void): Lee carácter de la consola con eco. Previamente, descarta cualquier dato almacenado en el buffer de entrada. Funciones de entrada y salida con formato:
Cuando se desea leer o escribir datos de un tipo diferente a caracteres en un fichero de texto, es necesario realizar una conversión de la representación interna de la máquina a una secuencia de caracteres, o viceversa. Esta conversión se especifica mediante una cadena de caracteres llamada formato. ∗ Salida con formato: Escribe un número variable de parámetros en la salida estándar. Sintaxis: ⇒ int printf( const char * formato, lista de variables ): Escribe un número variable de parámetros en la salida estándar, utilizando el formato que se especifica en su primer parámetro. Devuelve el número de caracteres escritos, o un valor negativo si ocurre algún error. En el formato pueden aparecer dos tipos de caracteres: ♦ Caracteres ordinarios: Se copian directamente en la salida.
Manual de Lenguaje C
Pág. 53
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
♦ Caracteres de especificación de conversión: Producen la conversión de valores de la representación interna de la máquina en una secuencia de caracteres. La función usa el formato para determinar el número y tipo de caracteres de los restantes parámetros, de forma que a cada especificación de conversión le corresponde el siguiente parámetro de la lista. Si no se pasan los suficientes parámetros, o son de un tipo distinto al especificado en el formato, se pueden producir resultados erróneos. Las especificaciones de conversión del formato comienzan con el carácter % y termina con el carácter de conversión. Entre el % y el carácter de conversión pueden especificarse, en el siguiente orden, los siguientes caracteres: ⇒ Signo - (menos): Que especifica un ajuste a la izquierda de los caracteres a escribir. ⇒ Número entero: Que especifica la anchura mínima, es decir el número mínimo de caracteres a imprimir. Si el parámetro convertido tiene menos caracteres que los estipulados, se añaden caracteres de relleno por la izquierda. Los caracteres de relleno son blancos, o ceros si la anchura mínima se especifica con un cero por la izquierda. ⇒ Punto: Que sirve para separar la anchura mínima de la precisión. ⇒ Número entero de precisión: La precisión estipula el máximo número de caracteres de una cadena, o el número de dígitos a escribir a la derecha del punto decimal en parámetros de tipo double. ⇒ Modificador de longitud l: Que indica que le correspondiente argumento es de tipo long, en vez de int. Los caracteres de conversión de salida son los siguientes: Conversió Tipo n d int o
Manual de Lenguaje C
int
Comentario El parámetro se convierte a notación decimal con signo. El parámetro se convierte a notación octal sin signo. Pág. 54
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
Conversió Tipo n x int u
int
c
int
s
char *
e
double
f
double
g
double
p
void *
Comentario El parámetro se convierte a notación hexadecimal sin signo El parámetro se convierte a notación decimal sin signo. El parámetro se convierte al correspondiente carácter del juego. Se imprime los caracteres de la cadena apuntada por el puntero que se pasa como parámetro, hasta encontrar el carácter nulo, o hasta que se impriman el número de caracteres especificados en la precisión. El parámetro se convierte a la notación exponencial de la forma: []m.ddddddE[+-]xx. La precisión por defecto es de 6 dígitos. El parámetro se convierte a la notación en coma fija de la forma: []m.dddddd. La precisión por defecto es de 6 dígitos. Usa la conversión que produzca menos caracteres de entre %e o %f. El parámetro se escribe como una dirección de memoria de la implementación usada.
⇒ int scanf (const char * formato, lista de parámetros): Lee caracteres de la entrada estándar, los interpreta de acuerdo al formato especificado en su primer parámetro, y almacena los resultados en las direcciones especificadas en los sucesivos parámetros, que deben de ser punteros. Devuelve el número de parámetros convertidos correctamente o EOF si se alcanza el final del fichero o un error antes de la conversión de alguno de ellos. Manual de Lenguaje C
Pág. 55
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
En el formato pueden aparecer tres tipos de caracteres: ♦ Espacios, tabulaciones y caracteres de control de línea: Provoca que se ignoren los blancos del flujo de entrada hasta encontrar un carácter no blanco. ♦ Caracteres ordinarios: Hace que se lea el siguiente carácter del flujo de entrada. Si el carácter leído no coincide con el carácter especificado en el formato, se detiene la ejecución del scanf. ♦ Caracteres de especificación de conversión: Provocan la conversión de valores de una secuencia de caracteres de la entrada a la representación interna de la máquina, almacenando el resultado en el correspondiente parámetro. Los caracteres de conversión de entrada son los siguientes: Conversió Tipo n d int *
o
int *
x
int *
h u c
short * unsig * char *
s
char *
Manual de Lenguaje C
Comentario Se espera un entero decimal en el flujo de entrada formado por un signo opcional y una secuencia de dígitos decimales. Salta blancos iniciales hasta encontrar un carácter no permitido. Se espera un entero octal con o sin signo. Se espera un entero hexadecimal con o sin signo se espera un entero corto. Se espera un entero sin signo. Se espera un único carácter. No se saltan blancos iniciales. Lee caracteres del flujo de entrada y se almacenan consecutivamente a partir de la dirección especificada hasta encontrar un carácter blanco o hasta que se hayan leído todos los caracteres estipulados en la anchura máxima. El carácter nulo se añade Pág. 56
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
e, f
float *
g
float *
automáticamente. Se saltan blancos iniciales. Se espera un número real formado por un signo opcional, una secuencia de dígitos, un punto decimal opcional, y un exponente opcional compuesto de E o e más un entero con signo opcional. Salta blancos iniciales. Idem a f y e.
Funciones de entrada y salida para cadena de caracteres:
Son funciones que sólo se pueden utilizar para leer o escribir cadenas de caracteres. ∗ char * gets (char *): Lee caracteres del flujo de entrada hasta el siguiente carácter ‘\n’, y los almacena en la cadena de caracteres apuntada por el puntero que se pasa como parámetro. En lugar de ‘\n’ se almacena ‘\0’. El array debe ser suficientemente grande para albergar todos los caracteres leídos. Devuelve la dirección que se pasa como parámetro, o NULL si se alcanza fin de fichero o si ocurre algún error. ∗ int puts (const char *): Escribe los caracteres del array apuntado por el parámetro hasta encontrar ‘\0’. En lugar de ‘\0’, escribe ‘\n’. Devuelve un valor no negativo si no hay error, o EOF si hay algún error. Acceso a ficheros:
El acceso a un fichero distinto de los ficheros estándar de entrada y salida requiere establecer una asociación entre un flujo de datos (fichero lógico) y el fichero físico. Esta asociación se realiza mediante la apertura del fichero, especificando su nombre; y se destruye mediante el cierre del fichero. Se distinguen dos mecanismos de acceso a ficheros: ∗ Acceso sin buffer: Los datos se transfieren entre la memoria y el fichero sin zonas de almacenamiento intermedio.
Manual de Lenguaje C
Pág. 57
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
Incluidas en el fichero <fcntl.h> en UNIX System V, y en el fichero <io.h> en MSC y TC. ⇒ int open (char * , int , int ): Abre un fichero, cuyo nombre se especifica mediante el primer parámetro. Devuelve un descriptor del fichero de tipo int, o -1 si hay error. El segundo parámetro especifica el modo de acceso al fichero, y puede ser el OR bit a bit de los siguientes valores definidos en <fcntl.h>: O_RDONLY Sólo lectura O_WRONLY Sólo escritura O_RDWR Lectura y escritura O_APPEND Escritura al final del fichero O_CREAT Si el fichero no existe, se crea. El tercer parámetro especifica los permisos que corresponden con los permisos UNIX sobre ficheros. Sólo tienen sentido cuando se crea el fichero. ⇒ int close (int): Cierra el fichero asociado a un descriptor de fichero. Devuelve 0 si no hay error , o -1 si hay error. ⇒ int read ( int, char *, int): El tercer parámetro indica el número de bytes que se leen del fichero identificado por el primer parámetro y los almacena a partir de la dirección especificada por el segundo parámetro. Devuelve el número de bytes leídos realmente, o -1 si hay un error. ⇒ int write ( int, char *, int): Escribe el número de bytes indicado mediante el tercer parámetro, en el fichero especificado por el primer parámetro, que se encuentran a partir de la dirección indicada mediante el segundo parámetro. Devuelve el número de bytes realmente escritos, o -1 si hay error. ∗ Acceso con buffer: Los datos se transfieren mediante zonas de almacenamiento intermedio que mejoran el tiempo de acceso a los datos, minimizando los accesos al fichero físico. Incluidas en el fichero <stdio.h>
Manual de Lenguaje C
Pág. 58
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
⇒ FILE * fopen (const char *, const char *): Abre el fichero cuyo nombre se especifica mediante una cadena de caracteres, indicada con el primer parámetro, y devuelve un puntero a una estructura de tipo FILE , o NULL si no se puede abrir. El segundo parámetro indica el modo de acceso al fichero, sólo puede haber tres modos de acceso, indicando lo siguiente: Lectura, los datos se transfieren del fichero al programa, escritura, los datos se transfieren del programa al fichero, y de actualización, donde se puede leer y escribir sobre el mismo fichero. Todos estos modos de acceso se especifican mediante una cadena de caracteres, que deben contener: modo de acceso r w
a r+ w+
a+
comentario Abrir fichero de texto para lectura. El fichero debe existir. Abrir el fichero de texto para lectura. Si existe, se borra su contenido previo; si no existe se crea. Abrir fichero de texto para escribir al final de su contenido previo. Si no existe, se crea. Abrir el fichero de texto para actualizar (escritura y lectura). El fichero debe existir. Abrir el fichero de texto para actualizar (escritura y lectura). Se borra el contenido previo, si existe. Abrir el fichero de texto para actualizar (escritura y lectura), escribiendo al final de su contenido.
rb, wb, ab, r+b, w+b, a+b. Idem para ficheros binarios. ⇒ int fclose (FILE *): Termina el acceso del fichero especificado mediante el identificador FILE, este debe ser un puntero obtenido mediante fopen. Si el fichero se abrió para lectura, se descartan los datos pendientes del Manual de Lenguaje C
Pág. 59
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
buffer de lectura. Si se abrió para escritura o actualización, se escriben en el fichero los datos pendientes del buffer de escritura. Devuelve 0 si no hay error, o EOF si hay error. ⇒ size_t fread ( void *, size_t, size_t, FILE *): Lee del fichero apuntado por el cuarto parámetro mediante el identificador FILE, un cierto número de objetos indicados por el tercer parámetro, de un cierto tamaño indicado por el parámetro segundo, y los almacena a partir de la dirección indicada en el primer parámetro. Devuelve el número de objetos leídos, que puede ser menor que el pedido en caso de error. ⇒ size_t fwrite ( void *, size_t, size_t, FILE *): Escribe en el fichero especificado con el cuarto parámetro, un cierto número de objetos, indicados por el tercer parámetro, de un cierto tamaño, indicado por el segundo parámetro, que se encuentran almacenados a partir de la dirección indicada por el primer parámetro. Devuelve el número de objetos escritos, que puede ser menor que el pedido en caso de error. ⇒ int fgetc(FILE *) o int getc(FILE *): Devuelve el siguiente carácter del fichero, o EOF si se encuentra fin de fichero o hay error. ⇒ char * fgets (char *, int, FILE *): Lee como máximo el número de caracteres especificados en el segundo parámetro menos uno, del fichero, y los almacena en la cadena especificada por el primer parámetro. Si se encuentra ‘\n’, se detiene la lectura y se copia en la cadena. La cadena se termina con ‘\0’. Devuelve la dirección de la cadena, o NULL si se alcanza fin de fichero o si ocurre algún error. ⇒ int fscanf (FILE *, const char *, lista de variables ): Es idéntica a scanf(), excepto que la lectura se realiza de un cierto fichero, en vez de la entrada estándar. ⇒ int fputc( int, FILE *) o int putc (int, FILE *): Escribe el carácter en el fichero. Devuelve el carácter escrito o EOF si hay error.
Manual de Lenguaje C
Pág. 60
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
⇒ int fputs (const char *, FILE *): Escribe los caracteres de la cadena indicada por el primer parámetro, en el fichero hasta encontrar ‘\0’. El carácter nulo no se escribe en el fichero, en su lugar no se escribe ‘\n’. Devuelve un valor no negativo si no hay error , o EOF si hay algún error. ⇒ int fprintf (FILE *, const char *, lista de parámetros): Idéntica a printf(), excepto que la escritura se realiza sobre un cierto fichero, en vez de sobre la salida estándar. ⇒ int fseek (FILE * , long, int): Permite fijar la posición del fichero sobre la que se realizará la siguiente lectura o escritura. Devuelve 0 si no hay error , y un valor distinto de 0 si hay error. Si el archivo es binario, la posición se fija por un desplazamiento en bytes sobre un valor origen. El origen que puede ser: SEEK_SET del principio del fichero SEEK_CUR de la posición actual SEEK_END del fin del fichero ⇒ int ffluhs (FILE *): Si el fichero está abierto para escritura, provoca que todos los datos pendientes en el buffer de escritura se escriban en el fichero. Si el fichero está abierto para lectura, el efecto está indefinido. Devuelve 0 si no hay error, o EOF si hay error. Tratamiento de errores:
Los mensajes de error de ejecución se escriben en el fichero estándar stderr. Además, en el fichero <errno.h> se declara una variable de tipo int llamada errno, que en cada momento contiene el valor correspondiente al último error acaecido en las llamadas a las diferentes funciones de las librerías. Las declaraciones de las funciones de error se encuentran en el fichero <stdio.h> . ∗ int feof (FILE *): Devuelve un valor distinto de 0 si se trató de leer tras el fin de fichero, en caso contrario devuelve 0. Manual de Lenguaje C
Pág. 61
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIÓN
∗ int ferror (FILE *): Devuelve un valor distinto de 0 si se ha producido un error en el acceso a un fichero, en caso contrario devuelve 0. ∗ void perror (const char *): Imprime en stderr un mensaje de error correspondiente al último error producido. Además , en <stdlib.h> se dispone de las siguiente declaraciones de funciones: ∗ void abort (void): Terminación anormal del programa. ∗ void exit ( int): Terminación normal del programa. Se vacían los buffers y se cierran los ficheros abiertos. Se devuelve el control al entorno del programa. El paso del valor entero al entorno es dependiente de la implementación, pero el valor 0 indica éxito.
Manual de Lenguaje C
Pág. 62
http://www.serem.com
Cliente: LUCENT TECHNOLOGIES
SEREM FORMACIร N
COMENTARIOS
Manual de Lenguaje C
Pรกg. 63
http://www.serem.com