You are on page 1of 56

Lenguaje de Programacin C

LENGUAJE DE PROGRAMACIN C
1. 2. 3. 4. 5. 6. Estructura de un programa Tipos de datos en C Constantes Identificadores Variables Modificadores Instruccin de asignacin Operadores Conversiones de tipos Funciones de E/S Sentencias de control 11.1. Seleccin 11.2. Bucles 11.3. Sentencias de salto 1 2 3 4 4 7 8 8 11 12 15 15 19 21 22 22 22 23 25 26 26 27 29 30 30

7. 8. 9. 10. 11.

12.

Arrays y cadenas 12.1. Introduccin 12.2. Arrays unidimensionales 12.3. Cadenas 12.4. Arrays bidimensionales 12.5. Arrays multidimensionales 12.6. Inicializacin de arrays 12.7. Arrays y punteros 12.8. Paso de arrays a funciones

13.

Punteros 13.1. Introduccin

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Pg. i

Lenguaje de Programacin C

13.2. Operaciones con punteros 13.3. Punteros a punteros 13.4. Problemas con punteros 14. Funciones 14.1. Introduccin 14.2. Prototipos 14.3. Paso de parametros 14.4. Argumentos de main: argv y argc 15. Estructuras de datos 15.1. Estructuras 15.1.1. Operaciones con estructuras 15.1.2. Estructuras complejas

....... ..

31 36 37 38 38 39 39

..... 40 41 41

.. 42 44 45 46 48 49 50 51 51 52

15.1.3. Paso de estructuras a funciones 15.2. Campos de bits 15.3. Uniones 15.4. Enumeraciones 15.5. Typedef 16. Gestin de memoria dinmica 16.1. Funciones 16.2. Arrays dinmicos 16.3. Estructuras de datos dinmicas

..... 53

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Pg. ii

Lenguaje de Programacin C

1.

ESTRUCTURA DE UN PROGRAMA

Un programa en C es una coleccin de una o ms funciones. Una funcin es una subrutina que contiene una o ms sentencias, y que lleva a cabo una o ms tareas. Cada funcin tiene un nombre y una lista de argumentos. En general se le puede dar a cada funcin el nombre que se quiera, excepto el de main, que est reservado para la funcin que inicia la ejecucin del programa (denominada funcin principal) y siempre debe de estar presente en cualquier programa de C. Estructura de un programa en C: Directivas de preprocesador (para incluir otros ficheros, definiciones de constantes y macros) Declaraciones globales (variables globales, prototipos de funciones, etc) tipo main ( lista_parametros ) { Declaraciones de variables locales Sentencias } tipo_retorno1 nombre_funcion1 ( lista_parametros ) { Declaraciones de variables locales Sentencias } . tipo_retornoN nombre_funcionN ( lista_parametros ) { Declaraciones de variables locales Sentencias } El compilador acepta cualquier patrn de saltos de lnea y sangras, sin embargo, los programas siempre deben organizarse de modo que sean fciles de leer. Primer programa en C // Un primer programa en C #include <stdio.h> int main() { printf (Empezamos con C); return 0; }

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Pg. 1

Lenguaje de Programacin C

Explicacin del programa: Comentarios de una lnea: cuando se usa un par de barras inclinadas seguidas (//) se est indicando que el resto de la lnea debe ser considerado como un comentario, es decir no causan ninguna accin al ejecutarse el programa sino que se aade para hacer ms comprensible y legible el programa. (Tambin existen los comentarios que contienen varias lneas, se inician con /* y terminan con */.) Las lneas que se inician con # son directivas del preprocesador. En concreto esta directiva include le dice al preprocesador que durante el lincaje incluya las funciones asociadas a la librera especificada entre < y > (en este caso es la librera estndar de entrada/salida stdio, que debe incluirse para que el programa pueda enviar salida a la pantalla o aceptar datos del teclado). La lnea int main () contiene la cabecera de la funcin main e indica el comienzo del programa. Los parntesis se usan para transferir parmetros a las funciones. En concreto, en este programa, la funcin principal no requiere transferir ninguna informacin, por lo tanto el contenido de los parntesis es nulo. Las llaves { }, indican el comienzo y final de una funcin, o en general, de un grupo de sentencias que constituyen un bloque. Cada { debe tener su correspondiente }, delimitando un bloque. Dentro de cada bloque pueden existir otros bloques anidados. El smbolo de punto y coma denominado terminador de sentencia forma parte de las sentencias, y va siempre al final de cada una. Se utiliza una funcin estndar denominada printf ( ) que se encarga de imprimir por la salida estndar, normalmente es la pantalla. Los parntesis indican que es una funcin, y tolo lo encerrado entre ellos es la informacin que se transfiere. La sentencia return, denominada instruccin de retorno, termina la ejecucin del programa y devuelve el control al sistema operativo. El nmero 0 se utiliza para indicar que el programa ha terminado correctamente. TIPOS DE DATOS EN C Los tipos de datos fundamentales en C son: a) Caracteres: char. Este tipo puede contener cualquier carcter individual almacenando el nmero entero correspondiente a dicho carcter segn el cdigo ASCII. Por ejemplo, en arquitecturas con palabras de 16 bits, un carcter ocupara 1 byte siendo por tanto su rango un entero entre -128 y 127, 256 elementos. b) Enteros: int. Un entero es un nmero sin punto decimal. Por ejemplo, en arquitecturas con palabras de 16 bits ocupan 2 bytes y su rango va de -32768 a 32767.
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 2

2.

Lenguaje de Programacin C

c) Coma flotante: representan nmeros reales que contienen punto decimal. float (reales en simple precisin). Por ejemplo, en arquitecturas con palabras de 16 bits ocupan 4 bytes, usando normalmente 8 bits para el exponente y 24 para la mantisa, por lo tanto un nmero real en simple precisin no tiene ms de 7 dgitos de precisin (significativos) y puede estar comprendido en el siguiente rango: -3.402823E+38 a -1.175494E-38 para nmeros negativos 1.175494E-38 a 3.402823E+38 para nmeros positivos double (reales de doble precisin) Por ejemplo, en arquitecturas con palabras de 16 bits ocupan 8 bytes, dando lugar a que tenga hasta 15 dgitos de precisin (significativos) y puede estar comprendido en el rango de: -1.79769E+308 a -2.22507E-308 para nmeros negativos 2.22507E-308 a 1.79769E+308 para nmeros positivos d) Nulo, vaco: void. No se pueden declarar variables de este tipo. Se usa: para indicar que una funcin no devuelve valor, para definir punteros genricos (todava no se sabe el tipo de dato al que va a apuntar). 3. CONSTANTES

Representan valores fijos que no pueden ser cambiados por el programa. C tiene cuatro tipos bsicos de constantes: 1.Constantes enteras: son nmeros sin parte fraccional, consistentes en secuencias de dgitos. Estas constantes se pueden escribir en tres sistemas numricos diferentes: decimal, octal y hexadecimal. Una constante entera hexadecimal consiste en 0x seguido de la constante en forma hexadecimal, mientras que una octal empieza por 0. Ejemplos: a) 0x80 128 decimal b) 0xFF c) 012 10 decimal d) 10 e) -100 Constantes en coma flotante: es un nmero con un punto decimal seguido de los nmeros de la componente fraccional. Ejemplos: a) 11.231 b) 0.18 c) 5.8e-7 Constantes de carcter: es un solo carcter encerrado entre comillas simples. Ejemplos: a) 'z' b) 3 c) ? Hay una serie de caracteres que son imposibles de introducir desde el teclado, por ejemplo salto de lnea, tabulador, etc. El C ofrece la posibilidad de introducir estos caracteres especiales como constantes, mediante lo que se denomina secuencias de escape o carcter de barra invertida. Una secuencia de escape siempre comienza con una barra inclinada hacia atrs seguida por uno o ms caracteres especiales. Se podra utilizar el valor correspondiente al carcter ASCII directamente, pero si se utiliza estos
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 3

2.-

3.-

Lenguaje de Programacin C

cdigos de barra invertida se asegura la portabilidad del cdigo. En la tabla que figura a continuacin vemos algunos de los caracteres de barra invertida (secuencias de escape) ms habituales:

Cdigo \b \f \n \r \t \v \a \0 \ \ \\ 4.-

Significado Retroceso de espacio Salto de pgina Salto de lnea Retorno de carro Tabulador horizontal Tabulador vertical Alerta (pitido) Nulo Comillas dobles Comillas simples Barra invertida

Constantes de cadena de caracteres: es una secuencia de caracteres entre doble comillas ("). No se debe confundir una constante de carcter 'a' con "a", que es una cadena que contiene slo una letra. Ms adelante se ver que esto implicar un tratamiento distinto. A veces es necesario incluir en una constante de cadena ciertos caracteres especiales (como la barra inclinada hacia atrs o las comillas) o ciertos caracteres no imprimibles (como el tabulador o el retorno de carro), para lo cual, se deben de representar en trminos de sus correspondientes secuencias de escape. Ejemplos: a) 123 b) Esto es una cadena\n IDENTIFICADORES

4.

Son nombres usados para referirse a variables, funciones y cualquier otro elemento definido por el usuario. Las siguientes normas son las que se deben seguir para su construccin: el primer carcter debe ser una letra o un smbolo de subrayado; los siguientes caracteres pueden ser letras, nmeros o caracteres de subrayado; se distinguen las maysculas de las minsculas (A y a son variables distintas); un identificador no puede ser igual a una palabra reservada en C y no debe tener el mismo nombre que cualquier funcin de la librera estndar. Ejemplos: Identificadores vlidos: suma, nota_media, des1, _temperatura, TABLA, des_1 Identificadores invlidos: 1nota, suma-total

5.

VARIABLES

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Pg. 4

Lenguaje de Programacin C

Una variable es una posicin de memoria con un nombre que se va a usar para mantener un valor que puede ser modificado por el programa. Todas las variables en C tienen que ser declaradas antes de usarse. La forma de declarar una variable es la siguiente: [modificadores] Tipo Nombre_variable1, Nombre_variable2, ..., Nombre_variableN; donde: modificador (opcional): indica una accin especial sobre la variable (tipo, almacenamiento o acceso). tipo: ha de ser un tipo de datos vlido. lista_de_variables: consiste en uno o ms nombres de variables separados por comas. Ejemplos: a) int i, j, k; b) float Nota_media; c) char carcter;

Existen tres lugares donde es posible declarar las variables: Dentro de las funciones: variables locales En la definicin de los parmetros de las funciones: parmetros formales Fuera de todas las funciones: variables globales VARIABLES LOCALES Son aquellas que se declaran dentro de las funciones o de los bloques ({}) y por lo tanto slo se pueden utilizar dentro de donde se definen; puesto que no son conocidas fuera de dicho bloque o funcin. Slo existen mientras se ejecuta el bloque, es decir; se crean al entrar y se destruyen al salir de l. Ejemplo: en la siguiente funcin, las variables x y j slo existirn durante la ejecucin de la misma. void funcin_1(void) { int x; char j='t'; ... } Si se desea ms legibilidad en el cdigo, las variables que se necesitan en una funcin se deben declarar al principio de la misma. Sin embargo, es posible declarar las variables en el momento de su utilizacin. Ejemplos: a) void funcin2(void) { int nota; scanf ("%d",&nota); if ( nota >= 5 ) { char nombre; ... }
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 5

Lenguaje de Programacin C

} La variable nombre se crea tras comprobar que la condicin del if es cierta y se destruye tras terminar dicha sentencia de seleccin, adems dicha variable slo es conocida dentro de ese bloque. La ventaja de declarar una variable en un bloque condicional es que slo se dispondr de la memoria necesaria para ella si se necesita, puesto que no existe hasta que se entra en el bloque en que est declarada. PARMETROS FORMALES Si una funcin usa argumentos, debe declarar las variables que van a aceptar los valores de dichos argumentos. stas se comportan como cualquier variable local, pudiendo ser usadas dentro de la funcin y siendo destruidas al salir de la misma. Sus declaraciones se dan tras el nombre de la funcin y entre parntesis, indicando de qu tipo son. Ejemplo: int mximo(int x, int y) { ... } Los parmetros formales deben de coincidir en tipo con los parmetros actuales (argumentos que se usan en la llamada a la funcin), si no es posible que se produzcan errores inesperados. Debido a que C permite bastante compatibilidad de tipos, es el programador quien la mayora de las veces tiene que comprobar sta. Para facilitar esta tarea es til el empleo de prototipos de funciones. VARIABLES GLOBALES Son variables que se conocen en todo el programa y se pueden usar en cualquier parte del cdigo, manteniendo su valor durante toda la ejecucin del mismo. Se crean al declararlas en cualquier lugar que est fuera de una funcin, aunque lo lgico es declararlas en la cabecera del programa. Si una variable local tiene el mismo nombre que una global, entonces todas las referencias a ese nombre dentro de la funcin donde ha sido declarada como local se refieren a esa variable local y no tienen efecto sobre la variable global. Se debe evitar el uso de variables globales innecesarias, por las siguientes razones: Utiliza memoria durante todo el tiempo de ejecucin del programa, no slo cuando se necesita. Hace que las funciones sean menos independientes y por tanto no facilita la programacin modular. Propicia la aparicin de efectos laterales, es decir; errores secundarios desconocidos y no deseables. Ejemplo: todo ello puede verse en las dos funciones que se exponen a continuacin. La primera de ellas permite calcular el mximo de dos nmeros cualesquiera (versin parametrizada), la segunda slo permitir calcular el mximo de las variables r y t, que,
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 6

1.2.3.-

Lenguaje de Programacin C

adems, debern estar definidas con anterioridad. GENERAL int maximo(int r,int t); { if (r>t) return(r); else return(t); } 6. MODIFICADORES ESPECFICA int r,t; int mul(void) { if (r>t) return(r); else return(t); }

Los tipos de datos bsicos pueden ser precedidos por distintos modificadores. Un modificador se usa para alterar el significado del tipo base, con el fin de que se ajuste ms concretamente a las necesidades de cada momento. A) MODIFICADORES DE TIPO Los modificadores de tipo son: signed (con signo), unsigned (sin signo), short (corto), long (largo). Todos ellos se aplican a los tipos int y char, mientras que al tipo double, slo se le puede aplicar long. (En general tamao (short) <=tamao (int) ) La siguiente tabla muestra las combinaciones posibles entre los tipos bsicos y sus modificadores, junto a los rangos obtenidos en arquitecturas con palabras de 16 bits.

TIPO TAMAO EN BYTES char (signed char) 1 unsigned char 1 int (signed/short/signed short) 2 unsigned int (unsigned short) 2 long int 4 unsigned long int 4 float 4 double 8 long double 10

RANGO MINIMO -128 a 127 0 a 255 -32768 a 32767 0 a 65535 -2147483648 a 2147483647 0 a 4294967295 7 dgitos de precisin 15 dgitos de precisin 19 dgitos de precisin

Cada tipo char tiene una representacin como entero equivalente, de esta forma un char es realmente una clase especial de entero corto. B) MODIFICADOR DE ACCESO Las variables definidas con el modificador const no pueden ser cambiadas durante la ejecucin del programa, pero si se le puede dar un valor inicial bien de una forma explcita o bien por algn medio dependiente del hardware. Ejemplo: const float iva=0,12;

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Pg. 7

Lenguaje de Programacin C

La definicin de variables const tiene dos aplicaciones bsicas: 1.- Para garantizar que un programa no modifica una variable. Se ha de indicar que una variable const puede ser modificada por algn agente externo al programa, como un dispositivo hardware. 2.- Pueden proteger los argumentos de una funcin para que estos no sean modificados. Cuando se pasa un valor por referencia puede modificarse la variable, pero si se define como de tipo const, la variable no puede ser modificada.

7.

INSTRUCCIN DE ASIGNACIN La sintaxis de la instruccin de asignacin es: nombre_variable = expresin; Ejemplos: i = 5; f = 3.2; c = a; b = false;

C permite usar el operador de asignacin con cualquier expresin vlida (combinacin de operadores, constantes y variables), incluso las que contengan operadores relacionales y lgicos, ya que para asignar un valor se hacen dos cosas: primero se evala la expresin y luego se asigna el valor de dicha evaluacin a la variable de la parte izquierda. C tambin permite incluir la instruccin de asignacin dentro de otras instrucciones. Ejemplo: if ((suma=nota1+nota2)<5) printf ( "Suspenso"); else printf ( "Aprobado); El destino (parte izquierda) debe ser una variable o un puntero, nunca una funcin o una constante. Inicializacin de variables: C permite inicializar una variable en el momento de su declaracin. Para ello se usa la siguiente notacin: [Modificadores] Tipo Nombre_variable=Constante; Ejemplos: double cuenta=9,98; int limite=10, factor=2; Las variables globales se inicializan slo al principio del programa, mientras que las locales se inicializan cada vez que se entra en la funcin en la que estn definidas. Asignacin mltiple: C tambin permite mediante una sola sentencia asignar a muchas variables el mismo valor. Ejemplo: x=y=z=0; 8. OPERADORES Operadores aritmticos. Los operadores +,-,* y / tienen el significado habitual, y pueden aplicarse a casi todos los tipos de datos permitidos en C, incluido el char. Cuando el operador / se aplica a operandos de tipo entero o carcter, cualquier resto es truncado (resultado de tipo entero). El operador monario
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 8

Lenguaje de Programacin C

menos (-) multiplica su nico operador por -1, es decir, cualquier nmero precedido por un signo menos, cambia de signo. El operador mdulo o resto de divisin entera (%), no puede usarse con los tipos de coma flotante (float, double). Los operadores de incremento (++ (aade uno a su operando)) y decremento (-- (resta uno a su operando)) pueden preceder o seguir al operando: i++ o ++i. La diferencia entre ellos consiste en que cuando el operador precede a la variable, el compilador realiza la operacin antes de utilizar el valor de dicha variable, mientras que en el caso de que el operador siga a la variable, el compilador realiza la operacin despus de usar la variable (cambia el valor por ejemplo en una asignacin). Ejemplo: las siguientes instrucciones ilustra la diferencia citada anteriormente: a) i=5; j=++i; /* i=6, j=6 */ b) i=5; j=i++; /* i=6, j=5 */ La prioridad o precedencia de los operadores aritmticos es la siguiente: ++, -mayor -(unario) * , /, % +, menor Los operadores del mismo nivel de precedencia son evaluados por el compilador de izquierda a derecha, siempre y cuando no se usen parntesis, puesto que estos alteran el orden de evaluacin ya que fuerzan a que una operacin, o un conjunto de operaciones, tengan un nivel de precedencia mayor. Operadores relacionales. Los operadores relacionales son: <, >, >=, <=, == (igual), != (distinto) y se pueden aplicar a operandos de cualquier tipo de dato (char, int, float y double). Operadores lgicos. Los operadores lgicos son: &&

(Y),

||

(O) ,

(No)

Las expresiones que utilizan los operadores relacionales y lgicos devuelven un valor que es o verdadero o falso. En C algo es verdadero siempre que sea distinto de cero y falso si es cero. verdadero = cualquier valor que no sea nulo falso = cero o nulo Tanto los operadores relacionales como los lgicos tienen un nivel de precedencia menor que los aritmticos. La prioridad entre ellos es: ! > >= < <= mayor

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Pg. 9

Lenguaje de Programacin C

== != && || menor De nuevo se pueden usar parntesis para alterar el orden natural de evaluacin en una expresin relacional o lgica. Operadores de asignacin adicionales C ofrece una serie de operadores de asignacin que actan como una notacin abreviada para expresiones utilizadas con frecuencia. stos son los siguientes: Operador += -= *= /= %= Ejemplo: a) c) e) Equivalencia a += b a=a+b a -= b a=a-b a *= b a=a*b a /= b a %= b Descripcin Suma b y a y el resultado se lo asigna a la variable a. Resta b de a y el resultado se lo asigna a la variable a. Multiplica a por b y el resultado se lo asigna a la variable a a = a / b Divide a entre b y el resultado se lo asigna a la variable a. a = a % b Le asigna a la variable a el resto de la divisin de a entre b. b) d) x = x-10; equivale a x -= 10; x = x /10; equivale a x /= 10;

x = x+10; equivale a x += 10; x = x*10; equivale a x *= 10; x = x %10; equivale a x %= 10;

Operadores de Direccionamiento e Indireccionamiento. Un puntero es la direccin de memoria de una variable. Una variable puntero se declara para contener un punter,o o sea una direccin a otra variable de un tipo especfico. Existen dos operadores bsicos para el tratamiento de variables de tipo puntero: a) & es un operador monario que devuelve la direccin de memoria del operando. Ejemplo: m = &cont; coloca en m la direccin de memoria de la variable cont. b) * es tambin un operador monario que devuelve el valor de la variable ubicada en la direccin que se especifica. Ejemplo: si m contiene la direccin de memoria de la variable cont, entonces la instruccin q = *m; colocar el valor de cont en q. Estos dos operadores tienen mayor precedencia que cualquier operador aritmtico, excepto el menos monario, respecto del cual la tienen igual. Las variables que vayan a contener direcciones de memoria (o sea, que sean punteros) deben declararse antes de ser usadas, mediante el siguiente formato: tipo_dato_apuntado * Nombre_variable_puntero; el * delante del nombre de la variable le indica al compilador que dicha variable va a contener un puntero a ese tipo de dato. Ejemplo: para declarar c como puntero a un carcter se tendr que escribir: char *c; El tipo de dato al que apunta un puntero se denomina tipo base del puntero, pero la
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 10

Lenguaje de Programacin C

variable puntero contiene la direccin de un objeto de dicho tipo base. Adems, un puntero slo se puede usar para apuntar a datos que sean del tipo base de dicho puntero. Se pueden mezclar declaraciones de puntero y variables normales en la misma sentencia. Ejemplos: int x, *y; declara x como de tipo entero, e y como puntero a un tipo entero. El siguiente programa muestra cmo se utilizan los operadores anteriores para copiar el contenido de una variable mediante su direccin. #include <stdio.h> int main() { int x, copiax; int *punt; x=10; punt=&x; copiax=*punt;

/* punt contiene la direccin de x */ /* copiax va a contener el valor almacenado en la direccin contenida en punt */ printf (Valor: %d , copiax); /* imprimir 10 */ return 0; } 9. CONVERSIONES DE TIPOS Las conversiones de tipos se utilizan para convertir un valor de un tipo a otro sin cambiar el valor que representa. Pueden ser: a) implcitas (ejecutadas automticamente): C realiza estas conversiones en los siguientes casos: a. cuando se asigna un valor de un tipo a una variable de otro tipo: se convierte el valor del lado derecho de la asignacin al tipo del lado izquierdo, pudiendo producirse prdidas de informacin o cambios en la representacin interna del valor. La siguiente tabla muestra las conversiones de tipo que se realizan automticamente y las consecuencias que se obtendra si se usa una arquitectura de palabras de 16 bits: b. Tipo destino signed char char char char short int short int Tipo de expresin char short int int long int int long int Posible prdida de informacin (palabras de 16 bits) Si valor>127, destino negativo 8 bits ms significativos 8 bits ms significativos 24 bits ms significativos Nada 16 bits ms significativos

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Pg. 11

Lenguaje de Programacin C

int int float double Ejemplo:

long int float double long double int i; char ch; float f; ch=i; i=f; f=ch; f=i;

16 bits ms significativos Parte fraccional y posiblemente ms Precisin, resultado redondeado Precisin, resultado redondeado

/* se pierden los bits ms significativos de i*/ /* se pierde la parte fraccionaria de f*/ /* cambio de formato, sin prdida*/ /* cambio de formato, sin prdida*/

c. cuando se combinan tipos mixtos en expresiones: se aplica la regla de promocin integral, que consiste en convertir los operandos al tipo del mayor operando. d. cuando se pasan argumentos a funciones. b) explcitas (solicitadas de forma especfica por el programador): aplicando el operador molde se puede forzar a que un valor sea de un tipo determinado. La forma general de un molde es: (tipo) expresin donde tipo es uno de los tipos estndar o uno de los definidos por el usuario. Por ejemplo, si se desea asegurar que la expresin x/2 se evale como un float aunque x sea un int, se debe escribir la siguiente sentencia: (float) x / 2 Los modes son considerados como operadores monarios y tienen la misma precedencia que cualquier otro operador monario. El siguiente fragmento ilustra la utilizacin de moldes, puesto que utiliza el mismo entero para controlar un bucle y para realizar un clculo que requiere parte fraccionaria. #include <stdio.h> void main(void) { /*imprime i e i/2 con fracciones */ int i; for(i=1;i<=100;++i) printf("%d/2 es %f\n",i,(float)i/2); } 10. FUNCIONES DE E/S La biblioteca de funciones incluye un cierto nmero de funciones de entrada/salida, a las
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 12

Lenguaje de Programacin C

que se puede acceder desde cualquier lugar de un programa escribiendo el nombre de la funcin, seguido de una lista de argumentos entre parntesis. Las funciones de E/S ms comunes son las dos siguientes: int scanf(const char *cadena_formato, arg1, arg2, , argn) Permite leer la entrada desde el dispositivo de entrada estndar, siendo la entrada cualquier combinacin de valores numricos, caracteres sueltos y cadenas de caracteres, es decir, lee cualquier tipo de datos y convierte los nmeros de forma automtica a su representacin interna apropiada. La funcin devuelve el nmero de datos que se han conseguido introducir correctamente y si se encuentra un fin de archivo prematuro, devuelve EOF. scanf Cadena_formato hace referencia a una cadena de caracteres que contiene cierta informacin sobre el formato de los datos. Para ello, esta informacin va a estar dividida en tantos grupos de caracteres como datos se van a leer, puesto que cada uno de ellos especifica el formato de los mismos. Cada grupo de caracteres comienza con el signo de porcentaje (%), seguido de un carcter de conversin que indica el tipo de dato correspondiente. La siguiente tabla muestra los caracteres de conversin ms usuales: Cdigo %c %d %e %f %h %o %s %x %p %u Significado Leer un nico character Leer un entero decimal Leer un nmero en notacin cientfica (notacin exponencial) Leer un nmero en coma flotante Leer un entero corto Leer un nmero octal Leer una cadena de caracteres Leer un nmero hexadecimal Leer un puntero Leer un entero sin signo en base decimal

Un carcter en blanco en la cadena de formato hace que esta funcin salte uno o ms caracteres en blanco de la secuencia de entrada. Un carcter en blanco es un espacio, una tabulacin o un carcter de salto de lnea. En definitiva, un carcter en blanco en la cadena de formato hace que esta funcin lea, pero no guarde, cualquier nmero de espacios en blanco hasta que encuentre el primer carcter que no sea de ese tipo. Por ejemplo, supngase la siguiente llamada a la funcin scanf: scanf(%s , nombre); , entonces esta funcin no termina hasta que no se introduzca un carcter de espacio en blanco despus de introducir un carcter, puesto que el espacio que hay detrs de %s indica que lea y descarte caracteres de espacios, tabulaciones y saltos de lnea. Un carcter distinto de espacio en blanco en la cadena de formato hace que la funcin lea y descarte los caracteres que coincidan con el mismo en la secuencia de entrada. Por ejemplo %d,%d hace que la funcin lea un entero, lea y descarte una coma y posteriormente lea otro
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 13

Lenguaje de Programacin C

entero. Si no encuentra el carcter especificado, la funcin termina su ejecucin. Otro ejemplo puede ser el siguiente, supngase que la llamada a la funcin es : scanf(%st%s, &x, &y); y que la secuencia de entrada es 10t20 , entonces en x se colocara 10 en y se colocara 20 y la t se descartara debido a la presencia de este carcter en la cadena de formato. Para cada uno de los datos que se introduce es necesario especificar la direccin donde van a ser almacenados, es decir los argumentos son punteros a las variables que se usan. Esta es la forma con la que se consigue realizar un paso por referencia y permitir que una funcin altere el contenido de un argumento. Por ejemplo, para leer un entero en la variable cuenta, se utiliza la siguiente llamada a la funcin scanf: scanf(%d, &cuenta); Los elementos de datos de entrada deben estar separados por espacios, tabulaciones o saltos de lnea. Los smbolos de puntuacin, tales como las comas, los punto y comas y similares no cuentan como separadores. Es decir, si la llamada a la funcin scanf es: scanf(%d%d, &r, &c); y la entrada es 10,20, entonces la llamada falla. Adems, los cdigos de formato deben corresponderse ordenadamente con las variables que van a recibir la entrada de la lista de argumentos. Las cadenas se asignan a vectores de caracteres y el propio nombre del vector (sin ndice) es la direccin del primer elemento del vector. Por lo tanto, para leer una cadena en un vector de caracteres se utiliza slo el nombre del vector sin tener que ir precedido por el operador &. Supngase el siguiente ejemplo: char cad[80]; scanf(%s, cad); Existe el modificador longitud mxima de campo que consiste en un entero situado entre el % y el cdigo de la orden de formato, que limita el nmero de caracteres ledos para ese campo. Por ejemplo, %20s leer como mximo 20 caracteres. De esta forma, si la entrada tiene ms caracteres que los indicados, una llamada posterior a la funcin scanf comenzar a leer donde la anterior acab. printf int printf(const char *cadena_formato, arg1, arg2, , argn)

Escribe cualquier combinacin de valores numricos, caracteres sueltos y cadenas de caracteres por el dispositivo estndar de salida, usando para ello formato. La cadena de formato puede contener caracteres que se muestran en la pantalla y rdenes de formato que definen la forma en que se muestran los argumentos. Una orden de formato empieza con un signo de porcentaje y va seguido por el cdigo del formato. La siguiente tabla muestra las rdenes de formato ms frecuentes: Cdigo %c %d %e Formato Visualiza un carcter Visualiza un entero decimal con signo Visualiza un real en notacin cientfica
Pg. 14

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Lenguaje de Programacin C

%f %o %s %u %x %% %p

Visualiza un real en decimal Visualiza un entero octal, sin el cero inicial Visualiza una cadena de caracteres Visualiza un entero decimal sin signo Visualiza un entero hexadecimal sin el prefijo 0x Visualiza un signo de porcentaje Visualiza un puntero

Los argumentos pueden ser constantes, referencias a funciones, variables simples o nombres de formaciones o expresiones ms complejas. Estos argumentos no representan direcciones de memoria y por tanto no son precedidos de &. Las rdenes de formato pueden tener los siguientes modificadores: especificador de longitud mnima de campo: es un entero situado entre el signo % y el cdigo de formato. Este modificador provoca que se rellene la salida con espacios para asegurar que el campo alcanza una cierta longitud mnima. Si se desea rellenar con ceros, es necesario poner un cero antes de este especificador. En el caso de que la cadena o el nmero sea ms largo que la longitud especificada, se visualizara en toda su longitud, aunque sobrepase el mnimo. Por ejemplo, %05d rellena con ceros un nmero que tenga menos de 5 dgitos para que su longitud sea cinco. especificador del nmero de posiciones decimales: consiste en colocar un punto tras el especificador de longitud de campo, seguido del nmero de decimales que se desea visualizar. Por ejemplo, %10.4f visualiza un nmero de al menos 10 caracteres con cuatro posiciones decimales. Si este modificador es aplicado a cadenas o a enteros, el significado consiste en especificar la longitud mxima del campo. Por ejemplo, %5.7s visualiza una cadena de al menos cinco caracteres y no ms de siete. Si la cadena es ms larga que la longitud mxima se truncarn los caracteres finales de la cadena. especificador de ajuste a la izquierda. Por omisin, todas las salidas se ajustan a la derecha, es decir, si la longitud del campo es mayor que el dato a imprimir, el dato se sita en la parte derecha del campo. Sin embargo, se puede forzar a que la salida se ajuste a la izquierda situando un signo menos directamente despus del %. Por ejemplo, %-10.2f hace que se ajuste a la izquierda un nmero real con dos espacios para decimales en un campo de diez caracteres. 11. SENTENCIAS DE CONTROL La mayora de las sentencias de control se basan en una prueba condicional que determina la accin a realizar. Dicha prueba condicional produce un valor que bien es cierto o falso. En C cualquier valor distinto de cero es cierto, y el cero es el nico valor que representa falso. 11.1. SELECCIN

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Pg. 15

Lenguaje de Programacin C

El C soporta dos tipos de sentencias de seleccin, simple y mltiple: if y switch. Seleccin simple: if La forma general de la sentencia if es: if(expresin) sentencia1; else sentencia2; donde tanto sentencia1 como sentencia2 pueden ser una instruccin simple o un bloque de instrucciones (conjunto de instrucciones encerradas entre { }) como se denota a continuacin: if(expresin) { secuencia de sentencias } else { secuencia de sentencias } La parte else es opcional y la expresin que se escribe entre parntesis, debe ser una expresin numrica, relacional o lgica. El resultado que se obtiene al evaluar dicha expresin es verdadero (no cero) o falso (cero), dando como consecuencia que se ejecute sentencia1 si el resultado es verdadero y sentencia2 si es falso. Ejemplo: El siguiente programa solicita dos nmeros y realiza la divisin entre ellos. Para ello, se va a usar una expresin numrica con la que se comprueba que el divisor no es cero. #include <stdio.h> void main() { int a, b; printf ("introduzca dos nmeros \n"); scanf ("%d%d",&a,&b); if(b) /* if(b != 0) */ printf ("%d",a/b); else printf ("No se puede dividir por cero"); } Es posible anidar ifs, es decir sentencia1 y sentencia2 pueden contener a su vez otras sentencias ifs. En C cuando existe duda sobre con que if se anida un else concreto, se sigue la siguiente regla: un else siempre se refiere al if anterior ms prximo que no est asociado ya con un else. Esta norma se puede anular utilizando llaves. Estas ideas se pueden ver reflejadas en el siguiente esquema de cdigo: if (expresin1) if (expresin1) { if (expresin2) sentencia1; if (expresin2) sentencia1; } else sentencia2; else sentencia2;
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 16

Lenguaje de Programacin C

// se asocia a if(expresin2)

// se asocia a if(expresin1)

Usando sentencias ifs anidadas se puede obtener una construccin comn denominada escala if-else-if, tal como se muestra a continuacin: if (expresin1) sentencia1; else if (expresin2) sentencia2; ... else sentencia_final; donde la primera expresin que sea cierta va a determinar la sentencia que se ejecuta. Si ninguna de las expresiones son ciertas se ejecuta el else final. El siguiente programa muestra como se usa la sentencia if para comparar dos nmeros. if(a > b) printf ("%d es mayor que %d",a,b); else if (a < b) printf ("%d es menor que %d",a,b); else printf ("%d es igual que %d",a,b); Operador ? El operador ternario ? tiene el mismo significado que una sentencia if/else, con la restriccin de que las sentencias deben ser expresiones simples. Su formato es: expresin1 ? expresin2 : expresin3 y es equivalente a la siguiente sentencia if: if(expresin1) expresin2; else expresin3; Es decir, se evala expresin1. Si es cierta, entonces se evala expresin2 y su valor se convierte en el valor de la expresin completa. Si expresin1 es falsa, entonces se evala expresin3 y su valor se convierte en el valor de la expresin completa. El siguiente ejemplo ilustra como se usa este operador para el clculo del mximo de dos nmeros: ... maximo = a>b ? a : b; printf ("El mximo es %d",maximo); ... El operador condicional (?) no slo se usa en sentencias de asignacin, sino que tambin
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 17

Lenguaje de Programacin C

es posible utilizarlo con funciones (salvo aquellas que no devuelven valor, es decir las declaradas como void), ya que estas devuelven un valor, que es el que toma la expresin (se ha de puntualizar que normalmente el valor que devuelve las funciones es ignorado). El siguiente trozo de cdigo ilustra esta idea: a > b ? printf ("El mximo es %d",a) : printf ("El mximo es %d",b); ... Utilizando la sentencia if/else se puede reescribir ste cdigo de la siguiente forma: if (a > b) printf ("El mximo es %d",a); else printf ("El mximo es %d",b); Seleccin mltiple: switch Esta sentencia compara el valor de una expresin con una lista de constantes enteras o de caracteres, y cuando encuentra correspondencia ejecuta las sentencias asociadas a la constante. Su formato general es: switch (expresin) { [declaraciones] case cte1: sentencia1; [break;] [case cte2:] [sentencia2;] [break;] ... [default:] [secuencia_final;] } donde: expresin es una expresin entera; ctei es una constante entera o de carcter o una expresin constante; en todos los casos, el valor resultante tiene que ser entero; sentenciai es una sentencia simple o compuesta; default determina las sentencias que se ejecutan si no se encuentra ninguna correspondencia. En definitiva, una sentencia switch comprueba el valor de la expresin con los valores de las constantes especificadas en los case, cuando se encuentra el valor adecuado se ejecuta la secuencia de sentencias asociadas a ese case, hasta que se encuentre la sentencia break o para el caso de las sentencias del default el final del switch (no es necesario este ltimo break).

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Pg. 18

Lenguaje de Programacin C

1.2.-

3.4.5.6.-

Con respecto a esta sentencia se ha de destacar los siguientes aspectos: La palabra default es opcional, si no est presente no se ejecuta ninguna accin al fallar todas las comprobaciones. La sentencia break es opcional, y se usa para finalizar el bloque de sentencias asociadas con cada constante, puesto que cuando se encuentra el break se salta a la siguiente lnea de cdigo despus del switch. Si en un bloque case se omite el break, entonces despus de ejecutar las sentencias correspondientes a ese case, se seguirn ejecutando las instrucciones del siguiente bloque case y asi sucesivamente hasta encontrar un break o el final del switch. La sentencia switch slo puede comprobar la igualdad. (Es la diferencia que existe entre esta sentencia y la sentencia if.) No pueden haber dos case con el mismo valor de constante. Un case puede tener sentencias vacias. La sentencias asociadas con cada case no forman un bloque en si, y por lo tanto, no se pueden declarar variables locales a esas sentencias. El siguiente ejemplo ilustra estas consideraciones: scanf (%c, &c) switch(c) { case '1': editar(); break; case '2': compilar(); break; case '3': depurar(); break; default: printf("Ninguna opcin seleccionada"); }

Anidamiento de switch: Se puede tener un switch formando parte de la secuencia de sentencias de otro switch. Incluso si las constantes case del switch interior y del exterior contienen valores comunes, no aparecen conflictos. 11.2. BUCLES Permiten repetir la ejecucin de un conjunto de sentencias hasta que se alcance una cierta condicin. Bucle for Cuando se desea ejecutar una sentencia simple o compuesta, repetidamente un nmero de veces conocido, la construccin adecuada es la sentencia for. Su formato general es: for (inicializacin; condicin; incremento) sentencia;
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 19

Lenguaje de Programacin C

En la inicializacin se suele dar un valor inicial a una variable de control del bucle. La condicin indica cuando finaliza el bucle. La prueba de la condicin se realiza siempre al principio, por lo tanto es posible que el cuerpo del bucle no se ejecute nunca pues la condicin sea falsa al comienzo. Supngase el siguiente ejemplo: x = 10; for ( y = 10; x != y; ++y) printf (%d, y); El incremento se utiliza para modificar el valor de la variable de control del bucle tras cada iteracin. El C permite muchas variaciones de la forma general del bucle for. Algunas de ellas son las siguientes: A) Permite hacer uso del operador "," con el fin de utilizar ms de una variable de control del bucle. Por ejemplo: for (i=0, j=99; i<j; i++, j--) ... B) Cada una de las tres secciones del for puede consistir en cualquier expresin vlida de C. for (inicilizar(); condicion(); actualizar()) ; C) Pueden omitirse todas las secciones de definicin del bucle puesto que son opcionales. Los siguientes for muestran esta variante: 1.for(;;) ; 2.x=10; for(; x!=20;) ++x; Bucle while while(condicin) sentencia; condicin sentencia es cualquier expresin numrica, relacional o lgica. puede estar vaca, o ser una sentencia simple o un bloque de sentencias.

Las acciones se repiten mientras la condicin es cierta, al finalizar el control continua con la sentencia siguiente al final del bucle. En el while, al igual que en el for, se comprueba la condicin al principio, con lo que se posibilita que el bucle no se ejecute ninguna vez. Las siguientes sentencias while muestran distintos ejemplos de la misma: 1.while (!final()) ...; 2.while (1) sentencia; /* bucle infinito */ Bucle do while do sentencia; while (condicin);
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 20

Lenguaje de Programacin C

Se repite sentencia mientras la condicin sea verdadera (hasta que la condicin se haga falsa). La evaluacin de la condicin se hace al final del bucle. As las sentencias del bucle siempre se ejecutan al menos una vez. El siguiente fragmento de cdigo muestra un ejemplo de como se utiliza esta sentencia: do { ... printf(Acabar (S/N)); scanf (%c, &c); } while (c!='S && c!='s'); 11.3 SENTENCIAS DE SALTO Estas sentencias hacen que el programa interrumpa su ejecucin normal y pase a ejecutar una determinada sentencia. break Se puede utilizar con cualquiera de las tres formas de bucle y con la sentencia switch. Produce un salto en el control del programa, de manera que se evita el resto del bucle o switch que lo contiene, y se reanuda la ejecucin con la siguiente sentencia a continuacin de dicho bucle o switch. Por ejemplo: for (;;) { ... if (cond) break; } return Se utiliza para indicar el valor de retorno de las funciones. Puede no llevar ningn valor asociado y no es necesario en funciones void. continue Fuerza una nueva iteracin del bucle y se salta cualquier cdigo que haya hasta el final del cuerpo del mismo. La diferencia en utilizarlo es bucles for es que es estos hace que se ejecute el incremento, antes de evaluar la condicin y si procede continuar la ejecucin del cuerpo del bucle. exit Fuerza la terminacin del programa. En realidad no es una sentencia, sino una funcin de la biblioteca estndar.
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 21

Lenguaje de Programacin C

void exit (int cdigo_de_vuelta);

// esta en stdlib.h

En cdigo_de_vuelta se indica un cdigo que se devuelve al proceso de llamada (posiblemente al sistema operativo), y que indica el tipo de terminacin (0 es terminacin normal). 12. ARRAYS Y CADENAS 12.1 INTRODUCCIN Un array es un conjunto de datos del mismo tipo y con el mismo tipo de almacenamiento que son referenciados por un nombre comn. A cada elemento individual se accede mediante el nombre del array seguido por uno o ms ndices encerrados entre corchetes. Cada ndice consiste en un entero no negativo que puede ser expresado mediante una constante entera, una variable entera o una expresin entera ms compleja. El nmero de ndices determinan la dimensin del array. En C los arrays se almacenan en posiciones de memoria contiguas, de la direccin ms baja que corresponde al primer elemento, a la ms alta que contiene el ltimo elemento. 12.2. ARRAYS UNIDIMENSIONALES. En C los arrays deben declarase explcitamente para que el compilador reserve la memoria necesaria para ellos. La forma general de declarar un array unidimensional es: tipo nombre_del_vector[tamao]; donde tipo constituye el tipo base del array, es decir el tipo de cada elemento del array, y tamao indica el nmero de elementos que contiene dicho array. Por ejemplo, la siguiente declaracin: int codigos[1000]; especifica un array compuesto por 1000 enteros. En C todos los arrays estn indexados desde cero, es decir, el ndice del primer elemento siempre es el 0. Por lo tanto, los ndices de la matriz anterior seran del 0 a 999. Supongamos el siguiente ejemplo, en el que se usa una funcin media para calcular la media de los nmeros enteros almacenados en un array. #include <stdio.h> int media (int elementos [ 10 ] ); void main (void) { int i, notas [10]; for ( i=0; i<=9; i++ ) { printf ("Introducir nmero %d: ",i); scanf ("%d",&notas [i]);
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 22

Lenguaje de Programacin C

} printf ("\nLa media de los nmeros vale %d",media(notas)); } int media (int elementos [10]) { int i, me = 0; for (i = 0; i <= 9; i++) me = me + elementos [i]; return (me / 10); }

El compilador de C no comprueba los lmites de los arrays, sino que es tarea del programador realizar la comprobacin de lmites cuando sea necesario. Si el programador no se ocupa de ello, es posible que se sobrepase cualquier extremo de un array y que se modifique cualquier otra variable de datos o incluso el cdigo del programa, siendo posible que el programa genere un error irrecuperable. 12.3 CADENAS. El array ms comn en C es la cadena de caracteres, que consiste en un array de caracteres terminado en un carcter nulo ('\0'). Dicho carcter indica el final de la cadena y se coloca automticamente cuando se define sta. Es por este motivo, que al declarar cadenas es necesario reservar espacio para un carcter ms que el requerido por la cadena de mayor tamao que se pueda almacenar. La siguiente declaracin define una cadena de caracteres con 10 caracteres como mximo. char codigo[11]; Aunque el tipo cadena, no esta definido como tal en C, si que se permite la utilizacin de constantes de cadenas, que no es ms que una secuencia de caracteres encerrada entre comillas dobles, donde no es necesario aadir explcitamente el carcter nulo, ya que el compilador lo hace automticamente. Para el manejo de cadenas C incorpora un gran nmero de funciones definidas en el archivo de cabecera string.h, siendo las ms usuales las siguientes: 1.char *strcpy(char *s1, const char *s2) Copia la cadena apuntada por s2 en la cadena apuntada por s1, devolviendo esta ltima. 2.char *strcat(char *s1, const char *s2) Concatena la cadena apuntada por s2 al final de la cadena apuntada por s1. Tambin devuelve s1. 3.int strlen(const char *s1) Devuelve la longitud de la cadena apuntada por s1. 4.int strcmp(const char *s1, const char *s2) Compara las cadenas apuntadas por s1 y s2 y devuelve uno de los siguientes valores: * 0 si las dos cadenas son iguales,
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 23

Lenguaje de Programacin C

5.6.-

* un entero menor que 0 si la cadena apuntada por s1 es menor que la apuntada por s2, * y, un entero mayor que 0 si la cadena apuntada por s1 es mayor que la apuntada por s2. char *strchr(const char *s1, int c) Devuelve un puntero a la primera ocurrencia de c en la cadena apuntada por s1. char *strstr(const char *s1, const char *s2) Devuelve un puntero a la primera ocurrencia de la cadena apuntada por s2 en la cadena apuntada por s1.

Para usar la funcin strcmp, no se puede olvidar que proporciona un valor falso cuando las dos cadenas coinciden y por tanto para hacer algo en el caso de que las cadenas sean iguales hay que utilizar el operador de negacin. Supongamos el siguiente programa, cuyo fin es el adivinar una cadena de caracteres. Para ello, se tiene hasta 10 posibilidades. #include <stdio.h> #include <string.h> #include <stdlib.h> #define clave "lpiic" La directiva #define permite definir constantes simblicas. Una constante simblica es un identificador que sustituye a una secuencia de caracteres. Estos caracteres pueden representar una constante numrica, una constante de carcter o una constante de cadena de caracteres (1). El compilador se encarga de sustituir cada aparicin de una constante simblica por su correspondiente secuencia de caracteres, salvo que el identificador aparezca dentro de una cadena (2). Estas constantes se suelen definir al comienzo del programa o incluso se incluyen en un fichero aparte, con el fin de no dispersar dichas definiciones por el programa. La forma general de esta directiva es: #define nombre texto donde nombre representa un nombre simblico y texto representa la secuencia de caracteres asociada al nombre simblico. Esta sentencia no acaba en punto y coma, ya que no se trata de una instruccin de C. Adems, se suele escribir en mayscula los nombres simblicos para distinguirlos de los identificadores ordinarios de C. Otro aspecto que se debe tener en cuenta, es que una constante simblica ya definida puede ser usada para definir otras (3). Ejemplos: (1) #define CADENA Esto es una cadena #define ENTERO 3 #define PI 3.141593 #define CAR a (2) #define CAD Prueba .............. printf(CAD); /* Visualiza CAD y no Prueba */ (3) #define UNO 1 #define DOS UNO+UNO
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 24

Lenguaje de Programacin C

int empezar (void); void main (void) { if ( empezar ( )) printf ("\nEmpieza el programa"); } int empezar (void) { char cad [20]; int cont = 0; do { printf ("\nintroducir contrasea : "); scanf (%s, cad); cont++; if (strcmp (cad, clave)) /* son distintas*/ printf ("\ncontrasea incorrecta"); if (cont==10){ printf ("\nse ha agotado el numero de posibilidades"); exit ( 1 ); } } while (strcmp (cad, clave)); return 1; } El hecho de que en C todas las cadenas terminen con un carcter nulo permite simplificar ciertas operaciones con cadenas, como por ejemplo utilizarlo como condicin de finalizacin para recorrer una cadena: for (i=0; cad[i]; i++) ... 12.4 ARRAYS BIDIMENSIONALES El C soporta arrays multidimensionales, el ms sencillo de ellos es el bidimensional. Estos se declaran de la siguiente forma: tipo nombre_arrray [tamao 1 dimensin] [tamao 2 dimensin] Por ejemplo, la siguiente declaracin define un array bidimensional de enteros: int matriz [30][50]; Para acceder a un elemento concreto es necesario especificar el valor de sus ndices (es decir, fila y columna) entre corchetes. Con nuestro ejemplo, si se desea acceder al elemento situado en la fila 15 y en la columna 40 se indicara: matriz [15] [40]

Arrays de cadenas
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 25

Lenguaje de Programacin C

Un caso particular de arrays bidimensionales son los arrays de cadenas. El tamao del ndice izquierdo determina el nmero de cadenas y el tamao del ndice derecho especifica la longitud mxima de cada cadena. Por ejemplo, la siguiente declaracin define un array de 24 cadenas, siendo 80 la longitud mxima de cada una de ellas (incluido el carcter nulo al final del array). char array_cadena [24][80]; Para acceder a una cadena concreta se debe especificar slo el primer ndice, como se puede observar en el siguiente ejemplo: scanf (%s, array_cadena[5]) 12.5 ARRAYS MULTIDIMENSIONALES C admite arrays de ms de dos dimensiones. La forma general de declarar arrays multidimensionales es la siguiente: tipo nombre[tamao 1 dimensin][tamao 2 dimensin][tamao n dimensin]; Para acceder a un elemento determinado de un array multidimensional, es necesario especificar el valor de sus ndices entre corchetes. Finalmente, se ha de tener en cuenta, que a medida que se incrementa el nmero de dimensiones de un array su uso es ms inadecuado debido a la cantidad de memoria requerida para su almacenamiento, y por la cantidad de tiempo empleado para el clculo de cada ndice. 12.6 INICIALIZACIN DE ARRAYS El C permite inicializar arrays en el momento de declararlos. Para ello, se usa la siguiente sintxis: tipo nombre_var[tamao 1 dim.][tamao 2 dim.]...[tamao n dim.] = {lista_de_valores}; donde lista_de_valores es una lista de constantes separadas por comas y cuyo tipo es compatible con el declarado para el array. La primera constante se coloca en la primera posicin del array, la segunda constante en la segunda posicin, y as sucesivamente. En el siguiente ejemplo, se inicializa un array de enteros de 10 elementos con los dgitos decimales: int digitos[10] = {0,1,2,3,4,5,6,7,8,9}; es decir, digitos[0] tiene el valor 0 y digitos [9] tiene el valor 9. Un array de caracteres puede ser inicializado usando la sintxis anterior, o de una forma ms abreviada, que consiste en encerrar entre comillas dobles la cadena a asignar. Por ejemplo, las siguientes inicializaciones producen el mismo resultado: char cadena[6]=texto; char cadena[6]={t,e,x,t,o,\0'}; Usando la forma abreviada no es necesario especificar el carcter nulo, puesto que este se
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 26

Lenguaje de Programacin C

aade automticamente al final de la cadena. Las siguientes inicializaciones muestran como se inicializan arrays multidimensionales: int notas [2][5] = { 5,7,3,4,9, 6,8,2,1,7}; char cad [4][5] = {yo, tu, el, ella}; Como resultado de dicha inicializacin, el elemento notas[0][0] contiene un 5, notas[0][1] contiene 7, notas[0][2] contiene un 3, notas[1][0] contiene un 6, y as sucesivamente. Inicializacin de arrays indeterminados: Si en una sentencia de inicializacin no se especifica el tamao del array, el compilador de C crea un array lo suficientemente grande para mantener todos los inicializadores presentes; es lo que se denomina array sin tamao o array indeterminado. Las siguientes inicializaciones usan arrays indeterminados: char error1[ ] = "error al abrir un fichero"; char error2[ ] = "error fichero no encontrado\n"; Se pueden usar arrays indeterminados para inicializar arrays de cualquier dimensin. En estos casos se deben especificar todas las dimensiones excepto la situada ms a la izquierda. Por ejemplo, a continuacin se muestra la inicializacin del array notas siendo indeterminado el nmero de filas: int notas [ ] [3] = { 3,6,4, 7,6,2, 1,8,6, 9,5,1}; La ventaja indudable de emplear arrays indeterminados es que se puede utilizar cualquier nmero de filas, aumentando o disminuyendo ste, en funcin de las caractersticas del problema. 12.7 ARRAYS Y PUNTEROS En C, arrays y punteros estn estrechamente relacionados. El nombre de un array es un puntero al primer elemento de dicho array. Por tanto, si codigos es un vector, entonces la direccin del primer elemento de dicho vector se puede expresar tanto como &codigos[0] o simplemente como codigos. Adems, la direccin del segundo elemento del vector se puede obtener tanto como con &codigos[1] como con (codigos +1), y asi sucesivamente. En general, la direccin del elemento i+1 del vector se puede expresar bien como &codigos[i] o como (codigos + i). En definitiva, existen dos mtodos para escribir la direccin de cualquier elemento de un
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 27

Lenguaje de Programacin C

vector escribiendo el elemento del vector precedido por &, o escribiendo una expresin en la cual el ndice se aade al nombre del vector. En este ltimo mtodo, el nombre del vector representa una direccin, mientras que i es una cantidad entera que especifica el nmero de elementos del vector que estan despus del primero. Se ha de tener en cuenta el tipo base del vector ya que este determina el nmero de posiciones de memoria usadas por cada elemento del vector, y por tanto i especifica un cierto nmero de posiciones de memoria ms all del primer elemento del vector. Puesto que &codigos[i] y (codigos + i) representan la direccin del i-simo elemento del codigos, parace razonable que codigos [i] y *(codigos + i) representen el contenido de esa direccin, es decir, el valor del elemento i-simo. Para entenderlo mejor se va a realizar un programa que visualice tanto el valor de cada elemento de un vector como la direccin correspondiente a dicho vector usando los diversos mtodos vistos anteriormente. #include <stdio.h> void main(void) { int x[10]={0,1,2,3,4,5,6,7,8,9}; int i; for (i=0; i<=9; i++) { printf(Valor del elemento i %d es: x[i]=%d, *(x+i)=%d, i, x[i], *(x+i)); printf(Direccin del elemento i %d es: &x[i]=%p, x+i=%p, i, &x[i], (x+i)); } } Por otra parte, tambin se puede generar un puntero al primer elemento de un vector, basta con asignarle a dicho puntero el nombre del vector sin ndices, o la direccin del primer elemento. Por ejemplo, en este array: int codigos[10]; int *p; p=codigos; /* es equivalente a p=&codigos[0]*/ las siguientes sentencias son iguales:

Como se vera en el apartado siguiente, a una variable puntero se le puede sumar o restar un valor entero, pero el resultado hay que interpretarlo como una nueva direccin que es la localizada a la distancia especificada por el entero a partir de la posicin original del puntero. Dicha distancia es el producto del entero por el nmero de bytes que ocupa cada elemento al que apunta el puntero. Adems, una variable puntero puede indexarse como si estuviese declarada como un vector. Teniendo en cuenta estas dos ltimas ideas y las sentencias anteriores, las siguientes asignaciones realizan el mismo efecto, es decir almacenar el valor 100 en el sexto
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 28

Lenguaje de Programacin C

elemento del vector codigos. p[5]=100; /* indexacin como vector del puntero */ *(p+5)=100; /* usando aritmtica de punteros */ La razn por la que se utilizan punteros en lugar de indexacin de arrays es que la aritmtica de punteros es ms rpida que la indexacin de arrays. 12.8. PASO DE ARRAYS A FUNCIONES. En general, en C no se puede pasar un array completo como argumento a una funcin, lo que se puede es pasar un puntero a un array especificando el nombre del array sin indice. Por ejemplo, en el siguiente trozo de cdigo se le pasa a la funcin definida la direccin del array declarado: void main (void) { int a[10]; funcion(a); ..... } Un array unidimensional se puede declarar como parmetro formal de tres formas: Como un puntero: func( int *p) { ... } Como un array delimitado: func( int p[10]) { ... } Como un array sin indice; es decir no delimitado. func( int p[]) { ... }

a)

b)

c)

Las tres declaraciones son equivalentes, ya que en cada caso se le indica al compilador que va a recibir un puntero a un entero, incluso en el caso de definirlo como p[10], no se reserva almacenamiento para 10 elementos, ya que C no comprueba los lmites de arrays y por tanto slo le interesa saber el tipo base. El paso de un array multidimensional como argumento de una funcin presenta una serie de salvedades. As, cuando se usa un array multidimensional como argumento de una funcin slo se pasa un puntero al primer elemento del array, es decir; basta con pasar el nombre del
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 29

Lenguaje de Programacin C

array sin ndices ni corchetes. Para especificar un array multidimensional como parmetro de una funcin se puede emplear los dos ltimos mtodos vistos anteriormente, es decir: como un array delimitado, o como un array no delimitado. Si se usa este ltimo mtodo es necesario definir todas las dimensiones excepto la dimensin de ms a la izquierda, lo cual es lgico por que el compilador necesita saber el tamao de cada dimensin para indexar el array correctamente. En concreto, si se trata de un array bidimensional, la funcin debe declarar al menos la longitud de la segunda dimensin, es decir definir la longitud de cada fila. Por ejemplo, la siguiente funcin recibe un array de enteros bidimensional declarado previamente: int p[5][10]; funcion( int p[][10]) { ... } En el caso de que el array sea de cinco dimensiones, por ejemplo, se deben especificar como mnimo el tamao de las cuatro ltimas: int p[4][5][2][6][3]; funcion(int p[][5][2][6][3]) { ..... } 13. PUNTEROS 13.1. INTRODUCCIN. Un puntero es una variable que contiene una direccin de memoria. Normalmente, esa direccin es la posicin de otra variable en memoria. Se dice que la variable puntero apunta a la otra variable. Como toda variable, los punteros deben ser declarados antes de ser usados. La forma general de declarar un puntero es la siguiente: tipo *nombre; donde: * tipo especifica el tipo base del puntero, que puede ser cualquier tipo vlido de C. Con l se define el tipo de variables a las que puede apuntar el puntero. * nombre es el identificador de la variable puntero. * el asterisco * identifica a la variable declarada como un puntero. Los operadores para el manejo de punteros son & y *: El operador & devuelve la direccin de memoria de su operando. El operador * es el complementario del anterior: devuelve el valor de la variable que est almacenada en la direccin que va a continuacin.
Pg. 30

* *

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Lenguaje de Programacin C

Ambos operadores tienen mayor prioridad que todos los operadores aritmticos, excepto el menos unario, respecto del cual tienen igual prioridad. Dentro de una declaracin de variables se puede inicializar una variable puntero asignndole la direccin de otra variable previamente declarada. Por ejemplo, supngase las siguientes declaraciones: float u; float *p=&u; /* Se asigna a p la direccin de u */ Adems, al definir un puntero se debe especificar a qu tipo de datos va a apuntar. Las variables puntero deben apuntar siempre al tipo de datos correcto, porque el compilador va a realizar todas las operaciones que se indiquen sobre el puntero, en funcin de ese tipo base. 13.2. OPERACIONES CON PUNTEROS. Asignacin de punteros: Un puntero se puede asignar a otro puntero. El siguiente programa muestra un ejemplo: void main (void) { int cod=20; int *p1,*p2; p1 = &cod; p2 = p1; printf (p1 : %p, p2 : %p, p1, p2); /* las direcciones contenidas en ambos punteros son iguales */ printf ("%d esta almacenado en %p", *p2,p2); } Operaciones aritmticas: Slo se pueden realizar dos operaciones aritmticas con punteros: suma y resta. Ambas se realizan teniendo en cuenta su tipo base, es decir; cada vez que se incrementa un puntero, ste apunta a la posicin de memoria del siguiente elemento de su tipo base, y cada vez que se decrementa apunta a la posicin del elemento anterior. As, si p1 es un puntero a un entero (se suponen enteros de 2 bytes) y su valor actual es 1000, despus de hacer p1++ , este contiene el valor 1002 puesto que apunta al siguiente entero. Lo mismo ocurre al decrementar, siendo 1000 el valor actual de p1, entonces despus de hacer p1-- su valor ser 0998. En definitiva, los punteros aumentan y decrecen en relacin a la longitud del tipo de datos a los que apuntan, puesto que siempre apunta al siguiente o al anterior elemento de ese tipo base.

rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino)

Pg. 31

Lenguaje de Programacin C

Los punteros no estn limitados slo a los operadores de incremento y decremento, sino que tambin se les pueden sumar y restar enteros. La asignacin p = p + 5, hace que p apunte al quinto elemento del tipo base definido ms all del elemento al que apunta actualmente p. Por ltimo, una variable puntero puede ser restada de otra siempre que ambas apunten a elementos del mismo array. El resultado indica el nmero de elementos que separan los correspondientes elementos del array. Supngase el siguiente trozo de cdigo: #include <stdio.h> void main(void) { int a[10]; int *p, *q; p = a; q = &a[9]; printf (Distancia entre el primer y ltimo elemento %x, q-p); } Cualquier otra operacin aritmtica distinta de las anteriores no esta permitida realizarla sobre punteros, como por ejemplo multiplicar o dividir punteros, sumar punteros, etc. Comparacin de punteros: Las variables puntero pueden ser comparadas mediante los operadores relacionales, siempre que sean del mismo tipo de datos. Una utilidad importante de la comparacin de punteros puede ser la de controlar el acceso dentro de los lmites de un vector de un tamao prefijado. El siguiente programa compara punteros con el fin de verificar los lmites de un array. /* Ejemplo de comparacin de punteros para verificar lmites de arrays */ #include <stdio.h> #include <stdlib.h> #include <conio.h> #define tam_pila 10 int menu(); void guardar(int e); int recuperar(void); void error(int op); /* El uso de variables globales no es aconsejable en la programacin modular */ int *tope, *p, pila[tam_pila]; void main(void) { int op,valor;
rea de Lenguajes y Sistemas Informticos (M Encarnacin Gonzlez Rufino) Pg. 32

Lenguaje de Programacin C

tope=pila; /* inicializar punteros de la pila */ p=pila; do { op=menu(); switch (op) { case '1':printf ("\nintroducir valor a guardar en la pila "); scanf ("%d",&valor); guardar (valor); break; case '2':printf ("\nvalor en el tope de la pila: %d", recuperar( )); getch ( ); break; case '3':; } } while (op!='3'); } int menu( ) { int op; do { clrscr(); printf("OPERACIONES CON UNA PILA\n"); printf("\t 1. Meter elemento en la pila\n"); printf("\t 2. Sacar elemento de la pila\n"); printf("\t 3. Salir\n"); printf("Introducir opcin: "); scanf (%c, &op); } while (op<'1' || op>'3'); return op; } void guarder (int e) /* En el primer elemento no se guarda informacin. Se guardan elementos mientras la pila no este llena. */ { p++; if (p==(tope+tam_pila)) error(0); *p=e; } int recuperar(void) /* Se recuperan elementos mientras la pila no este vacia */ { if (p == tope ) error(1); p--; return *(p+1); }

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 33

Lenguaje de Programacin C

void error(int cod) /* Ejemplo de vector de punteros */ { char *mensajes[] = { "Desbordamiento en la pila", "La pila esta vacia"}; printf("\n%s",mensajes[cod]); exit(1); } Arrays de punteros: Los punteros como cualquier otro tipo de datos, pueden estructurarse en arrays. Para asignar un valor a un elemento de dicho array, no se debe olvidar que ste tiene que ser una direccin de memoria. Por ejemplo, si se tiene en cuenta las siguientes declaraciones: int *vecpun[5]; /* array de punteros a enteros con tamao 5 */ int varint; /* variable de tipo entero */ Usando los operadores bsicos sobre punteros, se puede asignar la direccin de la variable varint a un elemento del array de punteros vecpun, mediante la siguente sentencia de asignacin: vecpun[3] = &varint; Posteriormente, para conocer el valor de varint, basta con escribir *vecpun[3] El siguiente programa muestra el uso de arrays de punteros. Este programa almacena en el vector indice las direcciones de los elementos 0, 4 y 8 del vector vector. Se puede observar, que usando las direcciones almacenadas tambin se puede conocer el contenido de esos elementos del vector vector. /* Ejemplo de arrays de punteros */ #include <stdio.h> void main(void) { int vector[12], *indice[3], i; /* carga de un vector de 12 elementos */ for (i=0;i<12;i++) { printf("\n Introduce elemento %d ",i); scanf("%d",&vector[i]); /* carga del vector de indices, agrupando los elementos de 4 en 4, por tanto 3 indices */ if ((i%4)==0) indice[i/4]=&vector[i];

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 34

Lenguaje de Programacin C

} /* listar indices, contenido y direcciones de memoria */ for (i=0;i<3;i++) printf("\nindice %d, contenido = %d, direccin %p", i, *indice[i], indice[i]); } Para pasar un array de punteros a una funcin, se usa la misma forma que para cualquier otro array, es decir; llamar a la funcin con el nombre del array sin ndices. De igual forma, para especificar un array de punteros como parmetro formal se usan los mismos mtodos usados para cualquier array. Con el fin de comprender mejor esta idea, el siguiente programa realiza la misma tarea que el anterior, usando una funcin para visualizar el contenido del array indice. Es por ello, que esta funcin va a recibir un array de punteros a enteros y por eso su parmetro formal especifica tal array (se puede observar que no es un puntero a un entero). /* Ejemplo de paso de arrays de punteros a funciones */ #include <stdio.h> void mostrar (int *q[]); void main(void) { int vector[12], *indice[3], i; /* carga de un vector de 12 elementos */ for (i=0;i<12;i++) { printf("\n Introduce elemento %d ",i); scanf("%d",&vector[i]); /* carga del vector de indices, agrupando los elementos de 4 en 4, por tanto 3 indices */ if ((i%4)==0) indice[i/4]=&vector[i]; } mostrar (indice); /* Se llama a la funcin mostrar */ } void mostrar (int *q[]) { int i; /* listar indices, contenido y direcciones de memoria */ for (i=0;i<3;i++) printf("\nindice %d, contenido = %d, direccin %p", i, *q[i], q[i]); } Una aplicacin de los arrays de punteros consiste en almacenar punteros que apuntan a mensajes de error. Se puede construir una funcin que visualice para un cdigo de error su mensaje correspondiente, tal como se muestra a continuacin: void error (int cod)
rea de Lenguajes y Sistemas Informticos (E.G.R.) Pg. 35

Lenguaje de Programacin C

char *mensajes[] = { "Desbordamiento en la pila", "La pila esta vacia"}; printf("\n%s",mensajes[cod]);

} Inicializacin de Punteros: Es fundamental recordar que despus de declarar un puntero pero antes de asignarle un valor, contiene un valor desconocido, por tanto, si se utiliza puede producirse cualquier efecto no deseado. Por convenio, a todo puntero que no apunte a ningn sitio se le debe asignar el valor nulo (NULL). Adems, es conveniente mencionar que el puntero nulo se suele usar para facilitar y realizar de forma ms eficiente el tratamiento de punteros. 13.3. PUNTEROS A PUNTEROS. Es posible hacer que un puntero apunte a otro puntero que a su vez este apuntando a un determinado valor, esto es lo que se conoce como indireccin mltiple. Indireccin simple: direccin ------------> valor (Puntero) (Variable) direccin --------> direccin --------> valor (Puntero) (Puntero) (Variable)

Indireccin mltiple:

La indireccin mltiple podra llevarse hasta el nivel que se desee, pero es muy extrao que sea necesario usar ms de dos niveles. La declaracin de un puntero a un puntero se realiza colocando un * adicional al nombre de la variable. Por ejemplo, la siguiente declaracin define un puntero a un puntero a un float: float **pp; Del mismo modo para acceder al valor apuntado por el puntero al puntero, es necesario poner **. En el siguiente ejemplo se puede observar la forma de acceder a un puntero a puntero: void main() { int x, *p, **pp; x=10; p=&x; pp=&p; printf ("%d",**p); /* imprime el valor de x=10 */ }

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 36

Lenguaje de Programacin C

13.4. PROBLEMAS CON PUNTEROS. Los punteros aportan potencia al C, pero a la vez su uso descontrolado puede causar graves problemas. Los errores que producen los punteros son normalmente difciles de detectar, ya que el problema no esta en el puntero sino en la zona de memoria donde se esta accediendo. A continuacin se comentan algunos de los errores ms comunes que surgen cuando se utilizan punteros: 1.) Puntero no inicializado: Consiste en utilizar un puntero que no contiene un valor vlido. Esto es una fuente de problemas, puesto que si se lee el contenido del puntero se obtiene cualquier valor invalido (basura), y si se escribe en el puntero se puede llegar a modificar parte del cdigo del programa, o de otros datos, lo cual puede generar un problema en otra parte del programa y ser difcil descubrir la causa real. El siguiente programa refleja este error, pues se asigna el valor de una variable a una posicin de memoria desconocida. void main() { int x, *p; x=10; *p=x; /* Se asigna el valor 10 a alguna posicin de memoria desconocida puesto que el puntero p nunca ha recibido un valor */ } SOLUCIN: asegurarse siempre que un puntero esta apuntando a un valor valido antes de utilizarlo. 2.) Asignacin a un puntero de un valor que no es una direccin. void main() { int x, *p; x=10; p=x; printf("%d",*p); } SOLUCIN: comprobar siempre que el valor asignado a un puntero es una direccin de memoria. 3.) Comparar punteros que no apuntan a objetos comunes. Esto produce resultados inesperados, puesto que no tenemos garanta de que el compilador almacene siempre las variables en memoria del mismo modo. char cad1[80], cad2[80]; char *p1, *p2;

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 37

Lenguaje de Programacin C

p1=cad1; p2=cad2; if (p1<p2) ... /* podr ser verdadero o podr ser falso */

14. FUNCIONES 14.1. INTRODUCCIN. Las funciones son los bloques constructores del C, el lugar donde se concentra toda la actividad del programa. La forma general de definicin de una funcin es la siguiente: tipo nombre_funcin(lista_parmetros) { cuerpo_funcin } donde: tipo

indica el tipo del valor que devuelve dicha funcin usando la sentencia return, si no se especifica ninguno, se asume que devuelve un entero (int). Cuando la funcin no devuelve ningn valor este tipo es void. lista_parmetros es una lista de variables junto con sus tipos separados por comas, que reciben los valores de los argumentos cuando se llama a la funcin. Todos los parmetros de la funcin deben incluir tanto el nombre como el tipo. Una funcin sin parmetros debe contener en el lugar de la lista de parmetros la palabra clave void. La sentencia RETURN sirve para:

Salir de una funcin devolviendo el control al punto donde fue invocada. Existen dos formas de terminar la ejecucin de una funcin y volver al punto en el que fue llamada. La primera, ocurre cuando se ejecuta la ltima sentencia de dicha funcin (conceptualmente la llave } del final). La segunda y la ms usada, consiste en usar la sentencia return, bien para devolver un valor o bien sin tener ningn valor asociado, slo con el fin de simplificar el cdigo y permitir que existan mltiples puntos de salida (una funcin puede tener varias sentencias return, aunque tener demasiadas puede romper la estructura de la funcin). 2 Devolver un valor al punto del programa donde se realizo la llamada. Todas las funciones, excepto aquellas de tipo void, devuelven un valor usando esta sentencia. Dicho valor puede ser usado como operando en cualquier expresin vlida de C. Del mismo modo, es obvio, que las funciones declaradas como void no pueden ser usadas en ninguna expresin.

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 38

Lenguaje de Programacin C

14.2. PROTOTIPOS. Su uso tiene como objetivo ayudar a detectar errores antes de que se produzcan. La sintaxis general de un prototipo es: tipo nombre_funcin(lista de parmetros); en donde: tipo representa el tipo de datos que devuelve la funcin y lista de parmetros identifica el nmero y el tipo de argumentos de la misma. Si la funcin no tiene parmetros se debe utilizar la palabra clave void como lista de parmetros. En definitiva, el uso de prototipos tiene dos funciones bsicas: Identificar el tipo que proporciona la funcin para que el compilador pueda generar el cdigo correcto (por defecto toda funcin devuelve un int, si no es asi, hay que indicarselo al compilador). Sirve para especificar el tipo y nmero de argumentos. No es necesario declarar los nombres de estos argumentos, aunque en la prctica si se incluyen.

Normalmente los prototipos de las funciones van o al principio del programa o en un archivo de encabezado y debe incluirse antes de hacer ninguna llamada a la funcin. Los prototipos permiten llevar a cabo una comprobacin estricta de tipos, puesto que se usan para comprobar cualquier conversin ilegal de tipos entre los tipos de los argumentos utilizados en la llamada a la funcin y los tipos definidos para los parmetros. Tambin permiten comprobar si el nmero de argumentos es o no incorrecto. Aunque C convierte el tipo del parmetro actual al tipo del parmetro formal, hay algunas conversiones que no son posibles. Por eso, se debe asegurar que los tipos de los parmetros y de los argumentos coincidan; en general, si hay un error en los tipos el compilador realiza, si es posible, la conversin entre ellos, pero esto puede implicar que se obtengan resultados inesperados. Por ejemplo, si se espera un puntero y se enva un entero, se interpretar el valor del entero como una direccin, dando lugar a que los resultados puedan ser impredecibles. 14.3. PASO DE PARAMETROS. Los parmetros tienen el mismo comportamiento que las variables locales de la funcin, es decir, se guardan en la pila y slo estn accesibles mientras se est ejecutando la funcin. Existen varias formas de pasar argumentos a una funcin: por valor: se copia el valor del argumento en el parmetro formal, y los cambios que se realicen sobre l no afectan a la variable que se usa en la llamada. por referencia: se copia la direccin del argumento en el parmetro, y se accede a esa posicin de memoria, por tanto los cambios que se realicen en la funcin afectan a la variable.

1.2.-

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 39

Lenguaje de Programacin C

La forma normal de realizar las llamadas en C es por valor. La llamada por referencia se realiza mediante punteros. Es decir, los argumentos que se pasan por referencia se definen como punteros y al invocar a la funcin se pasan direcciones de memoria, permitiendo que la funcin cambie el valor contenido en dichas posiciones de memoria. El siguiente programa ilustra esta forma de realizar llamadas por referencia. Su objetivo es que una funcin independiente, se encargue de leer del teclado dos enteros, los cuales sern visualizados por la funcin principal. #include <stdio.h> void leer_enteros(int *x,int *y); void main(void) { int a,b; leer_enteros(&a,&b); printf(Valores: %d %d,a,b); } void leer_enteros(int *x,int *y) { printf(Introducir dos enteros ); scanf(%d %d, x, y); } 14.4. ARGUMENTOS DE MAIN: ARGV Y ARGC. En determinadas situaciones es til pasar informacin a un programa en el momento de su llamada. Esto se consigue mediante el envo de argumentos a la funcin main (). Para ello, a la hora de ejecutar el programa en la lnea de rdenes del sistema operativo, se coloca despus del nombre de dicho programa, la informacin que se le desea pasar como argumentos. Existen dos argumentos especiales: argc y argv, que se usan para recibir los datos de la lnea de rdenes: 1 2 argc: contiene el nmero de argumentos y es de tipo entero. Siempre vale 1 por lo menos 1, ya que el nombre del programa es el primer argumento. argv: es un puntero a un array de punteros a char, cada uno de los cuales contiene uno de los argumentos. Cada argumento debe estar separado por un espacio o tabulador (no vale como separador la coma ni el punto). Si es necesario pasar un argumento que contiene espacios o tabulaciones, ste deber ser encerrado entre comillas. La forma del main en este caso es la siguiente: main(int argc, char *argv[]) { }

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 40

Lenguaje de Programacin C

El siguiente programa muestra el uso de estos argumentos con el fin de imprimir por pantalla el nombre del usuario dado desde la lnea de comandos. #include <stdio.h> #include <stdlib.h> void main(int argc, char *argv[]) { if(argc!=2) { printf("Olvid su nombre...\n"); exit(0); } printf("Hola %s",argv[1]); } 15. ESTRUCTURAS DE DATOS 15.1. ESTRUCTURAS. Una estructura es un conjunto de variables, relacionadas lgicamente, que se referencian bajo un mismo nombre. La declaracin de una estructura forma una plantilla, que puede usarse para crear variables con dicha estructura. El formato general que se sigue para la definicin de una estructura es la siguiente: struct [nombre_estructura]{ tipo nombre_elemento; ... } [variables_de_estructura]; donde nombre_estructura es el nombre de la estructura y no el nombre de una variable y nombre_elemento junto con su tipo son las declaraciones de los diversos elementos que componen dicha estructura. Con respecto a estos elementos individuales, se ha de mencionar que su tipo puede ser cualquiera de los tipos de datos bsicos existentes en C, punteros, arrays o incluso otras estructuras, y adems, que los nombres de dichos elementos deben ser diferentes dentro de una estructura, pero pueden coincidir con el nombre de otras variables definidas fuera de la estructura. Por ltimo, variables_de_estructura son una lista de nombres de variables separadas por coma, que son realmente las variables con la estructura especificada anteriormente. La siguiente declaracin muestra como se define una estructura y se declaran diversas variables con dicha estructura: struct libro{ char titulo[40]; char autor[20]; float precio; } l1, l2, l3;

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 41

Lenguaje de Programacin C

De la sintxis anterior, se puede observar que tanto el nombre_estructura como variables_de_estructura son opcionales. Si slo se necesita una variable con una estructura particular, no es necesario ponerle nombre a dicha estructura. Por ejemplo, la siguiente declaracin muestra esta idea: struct { char nombre[30]; char calle[40]; char ciudad[20]; }direccion; Por otra parte, puede interesar definir una estructura particular, y posteriormente declarar diversas variables con ese tipo de estructura; es decir omitir las variables de estructura. Entonces, para declarar despus variables con estructura se sigue la siguiente sintaxis: struct nombre_estructura variables_de_estructura; donde, de nuevo nombre_estructura es el nombre dado a la estructura en su definicin, y variables_de_estructura es la lista de variables separadas por coma que son declaradas con dicha estructura. Puede observarse el siguiente trozo de cdigo donde se refleja lo mencionado anteriormente: struct libro{ char titulo[40]; char autor[20]; float precio; }; struct libro l1; En resumen, tanto nombre_estructura como variables_de_estructura se pueden omitir, pero no ambas a la vez. 15.1.1. Operaciones con estructuras. Acceso a los elementos de una estructura. Los elementos individuales de una variable de estructura son referenciados usando el operador punto ".". Es decir, para referenciar un elemento individual de la estructura se utiliza el nombre de la variable de la estructura seguido de un punto y del nombre del elemento individual: variable_estructura.nombre_elemento Teniendo en cuenta las declaraciones realizadas en el aparado anterior, las siguientes sentencias muestran como se acceden a los elementos de una estructura. l1.titulo="Programacion en C++"; ... scanf (%s, l1.autor);

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 42

Lenguaje de Programacin C

Punteros a estructuras. Es posible definir punteros a estructuras, para lo cual, en la declaracin se antepone el smbolo * al nombre del puntero, tal como se expresa a continuacin: struct nombre_estructura *puntero_estructura; De nuevo, usando las declaraciones anteriores, la siguiente sera la declaracin de un puntero a una estructura: struct libro *pl, l1; Como cualquier puntero, los punteros a estructuras deben de apuntar al elemento adecuado antes de ser utilizados. Normalmente, esto conlleva almacenar en el puntero la direccin de una variable estructura previamente definida, como se indica en la siguiente sentencia: pl=&l1; Para acceder a cada elemento de una estructura a travs de un puntero, es necesario poner el nombre del puntero seguido del operador -> (se forma con un signo menos y un smbolo de mayor) y del campo concreto al que se desea acceder: puntero_estructura->nombre_elemento Por ejemplo, si se desea asignar valor al campo precio, las siguientes sentencias llevaran a cabo dicha tarea: p1->precio=5999; scanf(%f,&p1->precio); Asignacin de estructuras. De acuerdo con el estndar ANSI, puede asignarse la informacin contenida en una estructura a otra del mismo tipo. Dicha idea se ilustra en el siguiente programa: void main() { struct{ int a; int b; }x,y; x.a=10; y=x; /*se asigna una estructura a la otra*/ printf("%d",y.a); } Arrays de estructuras. Uno de los usos ms comunes de las estructuras son los arrays de estructuras. Para ello, se define primero la estructura y despus una variable array de ese tipo. De nuevo, teniendo en cuenta las declaraciones realizadas anteriormente, se puede declarar el siguiente vector cuyos

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 43

Lenguaje de Programacin C

elementos son estructuras: struct libro biblioteca[100]; Para acceder a una determinada estructura, se indexa el nombre del array. Por ejemplo, para visualizar el precio de la tercera estructura, la sentencia sera la siguiente: printf("%f",biblioteca[3].precio); 15.1.2. Estructuras complejas. Tambin es posible construir otros tipos de datos ms complejos, teniendo como base una estructura. Como elemento de una estructura se puede utilizar arrays e incluso nuevas estructuras. Arrays dentro de estructuras Es decir, un elemento de una estructura es un array. Supngase el siguiente ejemplo: struct{ int matriz[10][10]; int numero; }var; Para referenciar el entero cuya posicin es 3, 6 de matriz en la estructura var, se usa la siguiente sentencia: var.matriz[3][6]=9; Estructura anidada. Cuando una estructura es un elemento de otra estructura. Se pueden anidar estructuras hasta cualquier nivel. A continuacin se muestra un ejemplo: struct autor{ char nombre[20]; char apellidos[30]; }; struct libro{ struct autor primer_autor; char titulo[40]; float precio; }l; Para referenciar los elementos de una estructura anidada se usa repetidamente el operador punto, comenzando a referenciar los elementos de cada estructura ordenadamente desde el ms externo al ms interno. Teniendo en cuenta la estructura definida anteriormente, la siguiente sentencia accede a uno de sus elementos individuales. l.primer_autor.nombre=Pepe;

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 44

Lenguaje de Programacin C

15.1.3. Paso de estructuras a funciones. Es importante tener en cuenta cmo se puede realizar el paso de estructuras a funciones. Paso de elementos individuales. Cuando se pasa un elemento de una variable de estructura a una funcin, lo que realmente se est pasando es el valor de dicho elemento, o sea, se pasa una variable por valor. Si se desea realizar el paso por referencia, es necesario colocar el operador & delante del nombre de la estructura. Dadas las siguientes declaraciones de variables de estructura, las sucesivas llamadas a funciones realizan el paso por valor y por referencia: struct pieza { char codigo[8]; int unidades; float precio; } p1,p2; Paso por valor func1(p1.codigo[4]) func2(p1.unidades) func3(p1.precio) Paso por referencia func4(p2.codigo) /*pasa la direccin de la cadena */ func5(&p2.unidades) func6(&p3.precio) func7(&p2.codigo[2]) /*pasa la direccin del carcter */

Paso de estructuras completas. A una funcin se le puede pasar una estructura completa como argumento. A no ser que se indique lo contrario, el paso se realiza por valor y por tanto el contenido de la estructura no se vera afectado de los posibles cambios dentro de la funcin. Hay que destacar que el tipo del argumento debe ser compatible con el tipo del parmetro. Para ello, lo normal es definir la estructura globalmente, darle un nombre y definir tanto los parmetros actuales como los parmetros formales de ese tipo. El siguiente programa muestra un ejemplo de esto: #include <stdio.h> struct libro { char autor[40]; char titulo[40]; } void mostrar_autor(struct libro para_libro);

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 45

Lenguaje de Programacin C

void main(void) { struct libro l2; l2.autor=Federico Garcia Lorca; mostrar_autor(l2); return 0; } void mostrar_autor(struct libro para_libro) { printf(%s, para_libro.autor); } Cuando se pasa por valor una estructura a una funcin existe un inconveniente, se invierte mucho tiempo en el manejo de la pila (introducir/sacar cada elemento individual). Una posible solucin es pasar a la funcin un puntero a la estructura, o sea hacer un paso por referencia, en este caso slo se trabaja en la pila con un dato, la direccin de la estructura y adems se puede modificar el contenido de la estructura. En el siguiente ejemplo se realiza un paso de estructuras por referencia: struct fecha { int dia; int mes int ao }; void actualizar(struct fecha *f); ... Llamada a la funcin: struct fecha hoy; actualizar (&hoy);

Es conveniente recordar, que el operador punto se usa para acceder a elementos de estructuras cuando se trabaja directamente sobre ellas, y el operador flecha cuando se trabaja con un puntero a una estructura. 15.2. CAMPOS DE BITS El lenguaje C, permite acceder a un bit individual dentro de un byte. Sus ventajas son las siguientes: 1.Ahorra espacio puesto que permite la posibilidad de almacenar varias variables lgicas en un byte. 2.Las interfases de algunos dispositivos transmiten informacin codificada en los bits dentro de un byte. Puede ser considerado un ejemplo de la caracterstica de bajo nivel del

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 46

Lenguaje de Programacin C

3.-

lenguaje C. Permiten codificar/decodificar la informacin.

Un campo de bits no es ms que un tipo especial de elemento de estructura que define su tamao en bits. La sintaxis que se sigue par definir un campo de bits es: struct nombre_estructura{ tipo nombre1: longitud; tipo nombre2: longitud; ... tipo nombreN: longitud; }lista_variables; donde, longitud especifica el nmero de bits en el campo y ste debe ser un valor entero no negativo. Cada campo de bits debe declararse como int, signed o unsigned, pero si slo tiene un bit deber ser unsigned int (un slo bit no puede tener signo). Supngase el siguiente ejemplo: struct tipo_estado{ unsigned listo_enviar: 1; unsigned fin_tx: 1; unsigned on_line: 1; unsigned: 3; unsigned llamada: 1; unsigned: 1; }estado; Se puede observar, en la declaracin anterior, que no es necesario nombrar cada campo de bits, slo los que interesen. Las variables de campos de bits tienen ciertas restricciones: no se puede tomar la direccin de una variable de campos de bits, no se pueden construir arrays de variables de campos de bits, y cualquier cdigo que use campos de bits puede tener algunas dependencias de la maquina.

a) b) c)

Por ltimo, indicar que se pueden mezclar elementos de estructuras normales con elementos de campos de bits. Por ejemplo: struct empleado{ struct direccin dir; float paga; unsigned casado: 1;

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 47

Lenguaje de Programacin C

unsigned hijos: 3; }; Al igual que antes, se puede acceder a los miembros individuales de una estructura con campos de bits, utilizando el operador punto, o en el caso de que se trabaje con punteros usando el operador flecha. 15.3. UNIONES. Una unin es una zona de memoria que es compartida por varias variables, normalmente de distinto tipo, en distintos momentos. Es decir, los elementos que componen una unin comparten el mismo rea de almacenamiento, mientras que cada elemento de una estructura tiene asignada su propia rea de almacenamiento. Su sintaxis es similar a la de una estructura: union [nombre_union]{ tipo1 nombre_elemento1; tipo2 nombre_elemento2; ... tipon nombre_elementon; } [variables_union]; donde, union es una palabra reservada y nombre_unin es la etiqueta dada a dicha unin. Entre llaves, se encuentra la declaracin de los distintos elementos de la unin, para lo cual basta con indicar su tipo y nombre. Y por ltimo, variables_unin son la lista de variables que son de ese tipo de unin. La siguiente declaracin muestra un ejemplo: union tipo_u{ int i; char ch; } char_int; En este ejemplo, tanto el entero i como el carcter ch, comparten la misma posicin de memoria. Es decir, se puede referir al dato guardado como entero o como carcter. La siguiente figura muestra cmo comparten estos elementos la misma direccin: |<-----------i------------>| Byte 0 Byte 1 |<----ch---->| Al igual que las estructuras, nombre_unin y variables_unin son opcionales. Para declarar variables de unin de forma individual se usa la siguiente sintaxis: union nombre_union variables_union; Teniendo en cuenta la unin declarada anteriormente, la siguiente instruccin declara

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 48

Lenguaje de Programacin C

ms variables de ese tipo de unin: union tipo_u union1, union2; Cuando se declara una unin, el compilador crea una variable lo suficientemente grande para guardar el tipo ms grande de variable de la unin. (Slo se almacena uno cada vez). Para acceder a un elemento de la unin se usan los mismos operadores que en estructuras: . y ->. Si se est trabajando directamente con la variable unin, se usa el operador punto. Si se accede a dicha variable a travs de un puntero, se utiliza el operador flecha. Las uniones se usan frecuentemente donde se necesitan conversiones de tipos, ya que nos podemos referir a los datos de la unin de diferentes formas. 15.4. ENUMERACIONES. Una enumeracin es un conjunto de constantes enteras con nombre que especifican todos los valores vlidos que una variable de ese tipo puede tener. La forma general de declaracin es la que sigue: enum [nombre_enumeracin] {lista_constantes} [lista_variables]; donde enum es una palabra reservada, y el resto de trminos tienen el mismo significado que en una estructura. Tanto nombre_enumeracin como lista_variables son opcionales, pero debe estar presente alguna de ellas. La sintaxis que se sigue para declarar variables de enumeracin individuales (posteriormente a la definicin de una enumeracin) es la siguiente: enum nombre_enumeracin lista_variables; Las siguientes declaraciones muestran varios ejemplos de enumeraciones: enum moneda {peseta, duro, veinticinco,cien}; enum moneda dinero; enum fruta {pera, platano, manzana, uva} fruta_verano, fruta_invierno; Teniendo en cuenta lo anterior, las siguientes sentencias son vlidas: dinero=duro; (dinero=1;) if(dinero==peseta) printf("Podras ser ms generoso\n"); Es muy importante tener en cuenta que cada uno de los smbolos corresponde a un valor entero y recibe un valor mayor en 1 al que le precede. El valor del primer smbolo de la enumeracin es 0. De esta forma, pueden usarse en cualquier expresin entera. Por ejemplo: printf("Peseta vale %d, y veinticinco %d\n", peseta, veinticinco); Este ejemplo imprimir en pantalla 0 y 2. Por otra parte, se puede indicar el valor que se debe asignar a uno o ms smbolos

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 49

Lenguaje de Programacin C

especificando un iniciador, el cual se hace siguiendo al smbolo con el operador de asignacin y un valor entero. Se ha de tener en cuenta que los smbolos que siguen al inicializado tienen valores sucesivos a partir de este. Por ejemplo, la siguiente declaracin asigna el valor 5 a duro: enum moneda{peseta, duro=5, veinticinco}; Con lo que peseta valdra 0, duro 5 y veinticinco 6. Una suposicin errnea es que los smbolos pueden leerse y escribirse directamente. Esto no es as, el nombre que damos (peseta) es slo un nombre para un entero, no un string que puede leerse o escribirse directamente. Para mostrar en palabras el tipo de moneda que contiene dinero, se podra seguir la estructura siguiente: switch(dinero){ case peseta: printf("peseta"); break; case duro: printf("duro"); break; } Es posible, si no se usaron inicializadores (para que este indexado desde 0), declarar un array de cadenas con los nombres y utilizar el valor de la enumeracin como un ndice de dicho array, para traducir el valor de la enumeracin en su cadena correspondiente. Por ejemplo, el siguiente cdigo ilustra este mtodo: char nombre[]={"peseta","duro","veinticinco"}; printf("%s", nombre[dinero]); 15.5. TYPEDEF. Relacionado tambin con estructuras de datos ms complejas, estara la palabra reservada typedef, que permite definir explcitamente un nuevo nombre de tipo de dato. No se crea una nueva clase de datos, slo se le da un nuevo nombre para un tipo existente. Una vez que el tipo de datos definido por el usuario ha sido establecido, entonces las nuevas variables, formaciones, estructuras, etc., pueden ser declaradas en trminos de este nuevo tipo de datos. La sintxis que se sigue para declarar un nuevo tipo de datos es la siguiente: typedef tipo nuevo_nombre; donde tipo se refiere a un tipo de datos existente y nuevo_nombre es el nuevo nombre para ese tipo de datos. Este nuevo_nombre no supone un reemplazamiento del nombre de tipo existente, sino que es una adicin. La siguiente declaracin ilustra un ejemplo, donde se da el nuevo nombre edad al tipo de dato entero: typedef int edad; De esta forma, las siguientes declaraciones son equivalentes:

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 50

Lenguaje de Programacin C

edad x, y, z:

int x, y, z;

Tambin se puede crear nombres para tipos ms complejos, como muestra el siguiente ejemplo: typedef struct { char autor [20]; char titulo [30]; int precio; } libro; /* libro es el nuevo nombre del tipo */ libro l1, l2, l3; /* se definen variables de tipo libro */ Usando typedef se puede obtener un cdigo ms fcil de leer y ms fcil de transportar a una nueva mquina. 16. GESTIN DE MEMORIA DINMICA 16.1. FUNCIONES. Hay dos formas fundamentales con las que un programa puede almacenar informacin en la memoria principal: 1. Almacenamiento esttico: mediante variables reservadas en tiempo de compilacin, por lo tanto es preciso conocer de antemano la cantidad de espacio que se necesita. En el caso de variables globales, el almacenamiento se mantiene fijo durante toda la ejecucin del programa y se usa para ellas la Zona de Memoria de Variables Globales. Para las variables locales, el almacenamiento que se les asigna corresponde a la Pila. Almacenamiento dinmico: mediante espacio de memoria principal reservado dinmicamente y en tiempo de ejecucin. Es decir, el espacio de almacenamiento se asigna segn se necesite, devolvindose cuando se ha terminado con l. La zona del Montn (Heap) es la gestionada por la asignacin de este tipo de almacenamiento. En este caso la misma zona de memoria puede utilizarse para almacenar informacin diferente en distintos momentos de la ejecucin del programa. Se gestiona mediante la utilizacin de punteros. Las funciones que se utilizan para gestionar el heap son las siguientes: void *malloc(size_t num_bytes); stdlib.h

2.

El tipo size_t es un entero sin signo que est definido en el fichero de cabecera stdlib.h como para contener la mayor cantidad posible de memoria que se pueda asignar de una vez. Para facilitar el clculo del espacio que es necesario reservar se utiliza el operador sizeof. Esta funcin devuelve un puntero void al primer byte de una zona de memoria de num_bytes que se ha asignado del montn. Si no hay suficiente memoria libre en el montn devuelve un puntero nulo (NULL) indicando dicho error (es un buen hbito comprobar siempre que se ha

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 51

Lenguaje de Programacin C

obtenido un puntero vlido y garantizar la correcta utilizacin de punteros). Ejemplo: int *p; p = (int *) malloc (100 * sizeof ( int ) ); /* (1) y (2) */ if ( ! p ) /* (3) */ { printf("Error en la asignacin de memoria "); return (1); } 1. Se necesita convertir el puntero void a un puntero a un int. 2. Se utiliza la funcin sizeof para calcular el nmero de bytes que ocupa un entero. 3. Se hace una comprobacin de la correcta reserva de espacio. La comprobacin tambin puede realizarse de la siguiente forma: if ((p = (int *) malloc ( 100 * sizeof ( int ) ) == NULL) { printf ("Error en la asignacin de memoria"); return (1); } void free(void *p); stdlib.h

Esta funcin libera la memoria apuntada por p y que previamente fue asignada para que pueda ser reutilizada. Para evitar errores es importante utilizarla con punteros vlidos, es decir con los que previamente se haya reservado memoria dinmicamente. Ejemplo: free (p); 16.2. ARRAYS DINMICOS. En muchas situaciones de programacin, no es posible conocer el nmero de elementos que va a tener un array, por lo que no se puede utilizar un array predefinido ya que en ese caso habra que especificar sus dimensiones en tiempo de compilacin y stas no se pueden cambiar durante la ejecucin. Este problema se soluciona mediante la definicin de arrays dinmicos, arrays definidos en tiempo de ejecucin. Estos array usan memoria del heap y son accedidos indexando un puntero a dicha memoria. Ejemplo: int num_notas,i; float *notas_clase; scanf (%d, &num_notas);

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 52

Lenguaje de Programacin C

notas_clase = (float *) malloc (num_notas * sizeof ( flota )); if ( !notas_clase ) { printf (Error de asignacin de memoria); exit ( 1 ); } for (i = 0; i < num_notas; i++) scanf (%f, &notas_clase[i]); .... free (notas_clase);

Es conveniente comprobar el puntero que devuelve la funcin malloc con el fin de prevenir un uso accidental a un puntero nulo. 16.3. ESTRUCTURAS DE DATOS DINMICAS. Los arrays dinmicos tienen una limitacin, una vez creados no es posible alterar su tamao. Si el objetivo es disponer de un mecanismo para aumentar o disminuir el nmero de elementos segn la ejecucin del programa, se deben emplear estructuras basadas en la utilizacin de nodos. Un nodo es una estructura que consta de dos partes: una zona de datos donde se puede almacenar cualquier tipo de informacin, y una zona de punteros que contiene al menos un puntero que apunta a otro nodo. De esta forma, cada nodo puede estar situado en posiciones diferentes dentro de la memoria que no tienen porque ser contiguas. Normalmente, un grupo de nodos se asocia con una estructura de datos. A continuacin se examinan las siguientes estructuras de datos. Listas enlazadas Una lista enlazada es una coleccin lineal de nodos enlazados entre s mediante la zona de punteros que contiene un puntero al siguiente nodo. Por regla convencional, se marca el fin de la lista mediante el puntero nulo (NULL) en la zona de punteros del ltimo nodo. Para definir el nodo de una lista enlazada se puede utilizar la siguiente estructura: struct nodo { tipo informacion; struct nodo *siguiente; }; typedef struct nodo *posicion; typedef posicion lista; A la hora de reservar espacio para un nodo durante la ejecucin, se emplea la funcin malloc: posicion p; p=(posicion) malloc (sizeof(nodo));

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 53

Lenguaje de Programacin C

La funcin sizeof determina el tamao, en bytes, que ocupa la estructura nodo. La direccin de memoria que se obtiene se asigna a la variable puntero p que se declara previamente como un puntero a dicha estructura. Cada nodo se crea dinmicamente en funcin de las necesidades y se enlazan entre si todos los nodos que componen la lista. Es til implementar operaciones bsicas para manipulacin de la informacin en listas. Pilas Una pila no es ms que una lista LIFO, por lo que su implementacin es similar a la vista anteriormente: struct nodo { tipo informacion; nodo *siguiente; }; typedef nodo *pila; Las funciones tpicas de una pila son las de introducir (push) y extraer elementos (pop). rboles binarios Un rbol binario es una estructura de datos que contiene un campo de informacin y dos enlaces a otros nodos denominados hijo izquierdo e hijo derecho. Su implementacin en C sera: struct nodo { tipo informacion; nodo *hijo_izda; nodo *hijo_decha; }; typedef nodo *arbol;

rea de Lenguajes y Sistemas Informticos (E.G.R.)

Pg. 54

You might also like