introducción al lenguaje c

89
UNIVERSIDAD CATOLICA ANDRES BELLO GUAYANA Introducción al Lenguaje de Programación C Jesús J. Lárez M. [email protected] Octubre 2010

Upload: david-grilli

Post on 02-Jul-2015

2.297 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introducción al Lenguaje C

UNIVERSIDAD CATOLICA ANDRES BELLO

GUAYANA

Introducción al

Lenguaje de Programación C

Jesús J. Lárez M.

[email protected]

Octubre 2010

Page 2: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 2 de 89

"Si tú tienes una manzana y yo tengo una

manzana e intercambiamos las manzanas, entonces tanto tú como

yo seguiremos teniendo una manzana. Pero si tú tienes una idea y

yo tengo una idea e intercambiamos ideas, entonces ambos

tendremos dos ideas.“

George Bernard Shaw (1856 - 1950)

Dramaturgo y periodista irlandés.

Page 3: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 3 de 89

Contenido

Presentación

Historia y características del lenguaje C

Pasos para la creación de una aplicación en Lenguaje C

Entorno de Programación Integrado

Estructura de un programa en C

Identificadores

Palabras reservadas

Tipos de datos

Variables, alcance y tiempo de vida

Tipos de variables

Declaración de variables

Constantes

Operadores y expresiones

Instrucciones (sentencias ejecutables)

Funciones y parámetros

Arreglos, Estructuras, Uniones y Enumeraciones

Apuntadores

La biblioteca estándar

Entrada y salida

Memoria dinámica

Funciones con un número de parámetros variables

Pase de parámetros a la función main

El preprocesador

Llamadas a otros lenguajes de programación

Caso de estudio: implementar un comando del sistema

Algoritmos y aplicaciones

Bibliografía recomendada

Anexos

Page 4: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 4 de 89

Presentación

La presente guía nace como una necesidad de tener una herramienta concisa

para la enseñanza del lenguaje de programación C, en la Universidad Católica

Andrés Bello – Guayana. Está orientada como un instrumento de aprendizaje del

lenguaje y/o de consulta para los estudiantes de la carrera de Ingeniería en

Informática, con la finalidad de apoyar el uso el lenguaje tanto en cursos básicos

como el de Algoritmos y Programación y cursos avanzados tales como Sistemas

Operativos y Sistemas Distribuidos. Sin embargo la misma puede ser utilizada por

cualquier lector interesado en el aprendizaje o uso del lenguaje,

Se asume que el lector tiene nociones básicas en algoritmos y programación, es

por esta razón que se que desde un principio se muestran ejemplos de programas

completos para que el lector se inicie lo más pronto posible en el lenguaje. Sin

embargo los nuevos programadores, con nociones básica en ingles, podrán leer y

asimilar los concepto del lenguajes.

El contenido trata desde los usos más elementales hasta los más avanzados del

lenguaje. Mientras se abarca cada uno de los temas se muestran ejemplos de

programas completos y funcionales que ejemplifican los conceptos expuestos, la

idea es que el lector utilice estos ejemplos en el entorno de programación de su

preferencia, los compile y ejecute, observando y analizando tanto el código

como los resultados, para posteriormente modificarlos y experimentar. Estos

ejemplos intentan mostrar principios básicos de la programación tales como la

simplicidad, la claridad y la generalidad, con la finalidad que el lector pueda

desarrollar un buen estilo de programación, ya que un programa bien escrito es

más sencillo de entender y modificar; y tal vez lo más importante que tiene una

mayor probabilidad de ser correcto.

Page 5: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 5 de 89

Historia y características del lenguaje C

Este lenguaje fue diseñado originalmente para el Sistema Operativo UNIX en la

DEC pdp-11, en implantado en ella por Dennis Ritchie en los Laboratorios Bell,

aunque siempre ha estado estrechamente relacionado con UNIX no está ligado a

un Hardware o Sistema de Operación en particular. Aunque es un lenguaje para

la programación de sistemas debido a su uso en el desarrollo de Sistemas de

Operación, sin embargo C es un lenguaje de programación de propósito general,

es decir no está especializado en ninguna área de aplicación en particular es

decir se puede utilizar para varios propósitos.

El lenguaje C es caracterizado por ser conciso y poseer estructuras de control y

datos de alto nivel. Muchas de las características de C provienen del lenguaje

BCPL, inventado por Martin Richards, llegando indirectamente a través del

Lenguaje B, escrito por Ken Thompson en 1970 para el primer sistema UNIX en una

DEC pdp-7.

Durante años el estándar de C fue la versión proporcionada por la versión V de

UNIX. El cual aparece descrito en el libro ―The C. Programming Language‖ de

Brian Kernigham y Dennis Ritchie. En 1989 se define el primer estándar por ANSI,

que también fue adoptado por la ISO, siendo habitual que se le refiera como

estándar ANSI/ISO y se le conozca habitualmente como C89. Para 1995 aparece

la primera enmienda, que, entre otras cosas incorpora varias funciones de

bibliotecas nuevas. Siendo C89 y la enmienda 1 la base para C++. Para 1999

aparece una nueva versión de C (ANSI/ISO C99) donde se hace énfasis en la

incorporación de bibliotecas numéricas y arreglos de tamaño variable.

Al lenguaje C se le denomina como un lenguaje de nivel intermedio, es no

significa que sea menos potente, más difícil de utilizar o menos evolucionados que

otros lenguajes de alto nivel, sino más bien su significado es que combina

elementos de lenguajes de alto nivel con la flexibilidad y poder de los

ensambladores, permitiendo la manipulación de bits, bytes y direcciones, a pesar

de ello el código en C es muy portable. Esto le hace particularmente adecuado

Page 6: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 6 de 89

para la programación de sistemas.

Entre sus principales características, se puede mencionar:

Lenguaje programación de sistemas (UNIX), es decir es utilizado en para

programar partes del sistema de operación y/o utilidades, aunque es un

Lenguaje de propósito general.

Lenguaje de nivel intermedio, combina características de lenguaje de alto

nivel y la flexibilidad de los lenguajes ensambladores.

No es un lenguaje fuertemente estructurado, aunque posee estructuras de

control propias de lenguajes estructurado (while, do o for) tiene

instrucciones como goto, return, etc.

No es un lenguaje fuertemente tipeado permite que tipos diferentes lates

como caracteres y enteros se mezclen en una expresión así mismo permite

el uso incongruente de argumentos y parámetros en las llamadas a

funciones.

No comprueba errores durante la ejecución, tales como que se

sobrepasen los límites de los arreglos.

Código muy portable, es posible llevar o fácil de adaptar los programas

escritos a otro sistema de operación o hardware.

Un conjunto reducido de palabras reservadas.

Funcionalidades adicionales (I/O, matemáticas, memoria dinámica, etc.)

están disponible a través de bibliotecas estándar.

Lenguaje conciso con sobrecarga de operadores lo que puede dar a lugar

Programas Crípticos que pueden atentar contra la claridad.

Lenguaje simple, con funcionalidades añadidas por bibliotecas estándar.

Usa un lenguaje de preprocesado, el preprocesador de C se usa para

tareas como definir macros e incluir archivos al código fuente.

Soporta llamado recursivo de funciones.

Ofrece solamente el paso parámetros por valor.

Imposibilidad de anidar funciones.

Incluye apuntadores y aritmética de direcciones.

Page 7: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 7 de 89

Soporta compilación por separado.

Flujo de control sencillo, aunque no soporta multiprogramación,

paralelismo, sincronización o corrutinas.

En definitiva C, por sus características y eficiencia en un lenguaje para

programadores.

El lenguaje C ha influido a muchos lenguajes de programación entre los que se

puede mencionar: C++, java, JavaScript, C#, Objective-C, Perl, PHP, Python entre

otros.

Con la aparición de C++, se pensó que C dejaría de existir como lenguaje de

programación, pero no ha sido así en parte inmensa cantidad de sistemas y

aplicaciones en funcionamiento que desarrollada en C necesita mantenimiento,

no siempre se requiere la orientación a objeto de C++ por ejemplo aplicaciones

empotradas, a tiempo real o que requieran de mucha eficiencia.

Page 8: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 8 de 89

Pasos para la creación de una aplicación en lenguaje C

Los pasos para la creación de una aplicación en C son las siguientes:

Crear el programa fuente para lo cual se utiliza un editor.

Compilación del programa, C proporciona ciertas facilidades del lenguaje

por medio de un preprocesador, que conceptualmente es el primer paso

separado en la compilación, entre sus funcionalidades se pueden nombrar:

inclusión de archivos, substitución de macros, compilación condicional. Así

mismo C tiene soporte de compilación por separado, es decir se un

programa se puede escribir en múltiples archivos y cada uno de ellos

compilado por separado, lo cual tiene como ventaja en que un cambio en

uno de los archivos no requiere la compilación del programa completo.

Enlazar los diferentes módulos objetos, las bibliotecas requeridas y crear

archivo ejecutable

Opcionalmente depurar la aplicación.

A continuación se muestra un grafico con un ejemplo:

Ejecutable

Aplicacion.exe

Fuente

colas.c

Encabezado

colas.h

Objeto

colas.obj

Fuente

graficos.c

Encabezado

graficos.h

Objeto

graficos.obj

Fuente

Principal.c

Encabezado

colas.h

Objeto

Principal.obj

Encabezado

graficos.h

Encabezado

stdio.h

Librerias

.lib

Preprocesador

Compilador

Enlazador

Editor

[Depurador]

Page 9: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 9 de 89

Cuando se escriben programas, se pueden cometer errores (bugs). De hecho, los

programadores comenten errores y la probabilidad de que el programa funcione

a la primera vez es prácticamente cero. Por lo tanto, el desarrollo de un programa

siempre incorpora una etapa de depuración (debugging), que consiste en buscar

y resolver los errores cometidos durante la programación. Para facilitar la etapa

de depuración es conveniente usar herramientas especializadas para estos

efectos. La más común es el depurador o también llamado debugger.

Un depurador es una herramienta que permite intervenir durante la ejecución de

un programa, para saber cómo se está ejecutando. Un depurador permite, entre

otras funciones:

Ejecutar paso a paso un programa (stepping).

Establecer puntos de detención (breakpoints).

Examinar el contenido de las variables y objetos.

Conocer el encadenamiento de llamadas de procedimientos.

Retomar la ejecución hasta un nuevo punto de detención.

El proceso de compilación se puede automatizar utilizando la herramienta make,

la cual lee las instrucciones y las dependencias de un archivo (makefile) y ejecuta

los comandos que permiten generar el código ejecutable.

En nuestro caso en particular se ha utilizado el compilador gcc

(http://gcc.gnu.org/) y las herramientas gdb y make

Page 10: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 10 de 89

Entorno de Programación Integrado

Un entorno de programación integrado o en inglés Integrated Development

Environment (IDE) es una aplicación compuesta por un conjunto de herramientas

para programar, la cual puede estar dedicada de forma exclusiva a un sólo

lenguaje de programación o bien a poder utilizarse para varios.

Un IDE es un entorno de programación que ha integrado diferentes aplicaciones,

tales como: editores de código, compiladores, depurador, entre otras.

En nuestro caso en particular se ha utilizado el IDE eclipse (http://www.eclipse.org)

Page 11: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 11 de 89

Estructura de un programa en C

Los programas en C pueden estar formados por una o más funciones, aunque la

única función que debe estar presente en la función main(), siendo la función que

se invoca de primero cuando el programa se ejecuta, aunque main no es una

palabra clave se trata como si lo fuera, los programas en C tienen extensión .c

para los programas y .h para los encabezados (ya sean del programador o de las

librerías estándares).

Aunque un programa en C puede estar formado solamente por construcciones

propias del lenguaje, los compiladores de C incorporan bibliotecas estándar que

proporcionan funciones para algunas de las tareas más usuales, por ejemplo

entrada y salida ya sea por consola o por archivo, manejo de caracteres y

cadenas de caracteres, funciones matemáticas, manejo de memoria dinámica,

etc.

La estructura general de un programa en C, junto con nuestro primer programa

(en el archivo hola.c), se muestra a continuación

Declaraciones globales

tipo función(parámetros){

Declaraciones locales

secuencia de instrucciones

}

int main(int argc, char **argv){

Declaraciones locales

secuencia de instrucciones

}

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(void){

printf("Hello, world\n");

return 0;

}

/* --- Fin ejemplo --- */

La forma de compilar este programa, depende del sistema, en nuestro caso es

desde la línea de comando con gcc hola.c y se ejecuta con la orden a.out y

Page 12: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 12 de 89

siendo su salida

Hello, world

Analizando el programa se puede observar que:

Se considera comentario todo lo incluido entre /* y */. Siguiendo el

siguiente formato: /* comentario */ , un comentario puede ocupar varias

líneas y no pueden haber comentarios anidados, adicionalmente C99

permite comentarios en una sola línea comenzando con // y

extendiéndose hasta el final de la línea por ejemplo // comentario.

#include <nombre_archivo.h> es una directiva para el preprocesador que

incluye un archivo de cabecera (header) en este caso la biblioteca

estándar de entrada y salida.

Se define la función main() es la función principal del programa, es decir la

primera función a la que se llama dentro de la ejecución del programa y

que las instrucciones están entre llaves ("{" y "}") .

Se llama a la función printf() de la biblioteca estándar de entrada y salida,

la cual muestra la cadena de caracteres "Hello, world\n" en la salida

estándar.

Page 13: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 13 de 89

Identificadores

Un identificador, sirven para nombrar variables, etiquetas, y otros objetos definidos

por el programador, puede estar compuesto de cualquier combinación de letras

(minúsculas y mayúsculas), dígitos y el símbolo underscore '_'. La única restricción

es que el primer carácter debe ser una letra o un underscore. Un identificador no

puede coincidir con una palabra clave de C y con identificadores previamente

definidos en el mismo ámbito.

Ejemplos de identificadores:

Válidos:

x

y2

suma_1

_t

TABLA

No válidos:

4num primer carácter no es letra

―x‖ carácter ilegal “

orden-no carácter ilegal -

ind lis espacio ilegal

Observaciones

Se diferencia entre mayúsculas y minúsculas.

No se limita la longitud de los identificadores. Pero algunas

implementaciones sólo reconocen (son significativos) los 8 primeros y otras

(ANSI) los 31 primeros caracteres.

Page 14: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 14 de 89

Palabras reservadas (C89)

Las palabras reservadas de C, que no pueden ser utilizadas en definiciones por el

usuario son las que se listan en la siguiente tabla:

auto double int struct

break else long switch

case enum register typedef

char extern return union

const float short unsigned

continue for signed void

default goto sizeof volatile

do if static while

A las cuales C99 añade, entre otras:

inline Restrict

Page 15: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 15 de 89

Tipos de datos

C utiliza 5 palabras reservadas para definir los tipos de datos fundamentales. A

diferencia de otros lenguajes, un determinado tipo de datos puede ir cualificado

por un conjunto de modificadores.

Los tipos de datos fundamentales son:

char carácter

int entero

float real

double real doble precisión

void sin tipo

Todos los demás tipos se basan en los anteriores

Modificadores:

signed con signo

unsigned sin signo

short corto

long largo

A continuación se muestra una tabla con los tipos, su tamaño en bits y el rango

de valores que puede almacenar, esto puede variar por cada tipo de

procesador.

Tipo Tamaño Bits Rango de valores

char 8 -128 a 127

unsigned char 8 0 a 255

signed char 8 -128 a 127

int 16 (o 32) -32.768 a 32.767

unsigned int 16 (o 32) 0 a 65.535

signed int 16 (o 32) -32.768 a 32.767

short int 16 -32.768 a 32.767

unsigned short int 16 0 a 65.535

signed short int 16 -32.768 a 32.767

Page 16: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 16 de 89

long int 32 -2.147.483.648 a 2.147.483.647

unsigned long int 32 0 a 4.294.967.295

signed long int 32 -2.147.483.648 a 2.147.483.647

long long int 64 Añadido por C99

unsigned long long int 64 Añadido por C99

enum 16 0 a 65.535

float 32 3,4E-38 a 3,4E+38 (7 dígitos)

double 64 1,7E-308 a 1,7E+308 (15 dígitos)

long double 64 1,7E-308 a 1,7E+308 (15 dígitos)

El lenguaje C no incorpora el tipo de dato lógico (boolean) para lo cual se utiliza

un entero, interpretándose todo valor distinto de 0 como verdadero y el valor 0

como falso.

Se pueden definir nuevos nombre para los tipos de datos existentes utilizando la

palabra clave typedef, que realmente no crea un nuevo tipo de datos sino que

define un nuevo nombre para un tipo ya existente. La forma de utilizarlos es:

typedef tipo nombre;

Donde tipo es cualquier tipo de datos valido, ya sea un tipo base o una

estructura, por ejemplo:

typedef unsigned char byte;

El programa a continuación muestra el tamaño de las diferentes tipos, para lo

cual usaremos el operador sizeof que calcula el tamaño, en bytes, de cualquier

tipo o variables.

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

Page 17: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 17 de 89

int main(void){

int a;

float f;

printf("Size of char: %d\n",sizeof(char));

printf("Size of short: %d\n",sizeof(short));

printf("Size of int: %d\n",sizeof(int));

printf("Size of long int: %d\n",sizeof(long int));

printf("Size of float: %d\n",sizeof(float));

printf("Size of double: %d\n",sizeof(double));

printf("Size of a: %d\n",sizeof(a));

printf("Size of f: %d\n",sizeof(f));

return 0;

}

/* --- Fin ejemplo --- */

Page 18: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 18 de 89

Variables, alcance y tiempo de vida

La posición de memoria con un nombre que se utiliza para mantener un valor que

puede ser modificado durante la ejecución del programa se le conoce como

variable.

Asociado a una variable se pueden distinguir tres conceptos: el identificador, su

tipo y su valor. El identificador es el símbolo que la nombra y el tipo define lo que

puede almacenar la variable y el conjunto de operaciones que pueden aplicar,

por ejemplo para la siguiente declaración

int n = 123;

Se puede distinguir

Ahora veamos algunas definiciones relacionadas con las variables:

Un binding es una asociación entre dos cosas, por ejemplo un nombre de

variable con su contenido (el elemento que denota).

Tiempo de vida de una variable: El tiempo de vida se refiere al intervalo de

tiempo que trascurre desde que se crea la variable hasta que se destruye.

Alcance de una variable: El alcance de una variable es el conjunto de

instrucciones en la que esa variable es visible por medio de su identificador.

Es importante entender la diferencia entre alcance y tiempo de vida de una

variable. Si una variable no es visible, no necesariamente ha sido destruida. En

cambio, si una variable fue destruida, esa variable no es visible.

Page 19: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 19 de 89

Tipos de variables

Un programa compilado en C tiene cuatro regiones lógicas de memoria

diferentes, las cuales se muestran a continuación:

Aunque la disposición física de cada una de ellas puede diferir entre los diferentes

tipos de procesadores y entre las diferentes implementación del lenguaje. La

figura anterior muestra de forma conceptual como aparece un programa en C

en la memoria. La primera región contiene el código del programa, en la

siguiente región se guardan las variables globales (datos estáticos) ambas

regiones se asignan en tiempo de compilación. Las dos regiones restante son

asignadas en tiempo de ejecución y son la pila (stack) y el montón (heap), la pila

mantiene entre otros las direcciones de retornos, los parámetros reales y las

variables locales (datos automáticos) y finalmente el montón es la región que

puede utilizarse, de forma explícita, mediante las funciones de administración de

memoria dinámica (datos dinámicos) y se utilizan a través de apuntadores

(pointers).

Page 20: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 20 de 89

Declaración de variables

La forma general de declaración es:

<tipo> lista_de_variables;

int numero1, numero2;

long int l;

Las variables globales y static solo son inicializadas al principio del

programa, las variable locales automáticas se inicializan cada vez que se

entra en el bloque. Las variables globales y static que no hayan sido

inicializadas toman automáticamente el valor inicial de cero y las locales

auto tendrán valores desconocidos.

Inicialización de variables en la declaración

El esquema para la inicialización de variables en la declaración es el siguiente:

<tipo> nombre_variable = valor;

int numero1=5,numero2;

Dónde se declaran las variables

Básicamente hay tres sitios donde se pueden declarar variables: dentro de las

funciones, en la definición de los parámetros de las funciones y fuera de todas las

funciones. Estas variables se denominan, respectivamente, variables locales, los

parámetros formales y variables globales.

Variables locales, parámetros formales y variables globales

El lugar donde se declara una variable define el ámbito que determina el

alcance o visibilidad de la variable por medio de su identificador. Hay que

recordar que dentro del mismo ámbito no se pueden realizar declaraciones con

el mismo identificador

Page 21: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 21 de 89

Variable local: A las variables locales que se declaran dentro de una

función nos referimos a ellas como variables automáticas. Solo puede ser

utilizada dentro del bloque en el que han sido declaradas o expresado de

otra forma, las variables locales no son conocidas fuera del bloque de

código donde han sido declaradas. Un bloque de código comienza con

una llave que abre { y termina con una llave que cierra }, se pueden

declarar variables locales en cualquier bloque, el bloque definido por una

función es solo un caso especial. Las variables locales solo existen mientras

se está ejecutando el bloque de código donde está declarada, es decir se

crean al entrar y destruyen a salir de él y su valor se pierde, esto es

particularmente importante en las llamadas a funciones ya que no pueden

retener su valor entre llamadas, sin embargo se usando el calificador static

se crea un almacenamiento permanente con alcance en el bloque.

Parámetros formales: Si una función utiliza argumentos, debe declarar las

variables que aceptarán los valores de los argumentos, esas variables son

los parámetros formales de la función y se comportan como cualquier otra

variables local de la función. Hay que tener presente que al igual de las

variables locales son automáticas y se destruyen al salir de la función.

Variables globales: A diferencia de las variables locales, las variables

globales se conocen a lo ―largo del todo programa‖ y se puede utilizar en

cualquier parte del código, además mantienen sus valores durante toda la

ejecución del programa. Son variables que declaran fuera de todas las

funciones.

En la práctica ocurre que cada identificador solo tiene alcance (es visible) en

algunas regiones de su ámbito, que podrían ser discontinuas. La razón por la que

un identificador deja de tener alcance (o ser visible) dentro de su ámbito es que

sea ocultado por otra declaración explícita que utiliza el mismo identificador. La

nueva declaración puede ocurrir por ejemplo en un bloque de código anidado

(recordemos en el mismo no es posible una nueva declaración con el mismo

identificador) o dentro de una función en el caso de variables globales.

Page 22: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 22 de 89

Como se pudo observar dependiendo del sitio donde se declaren las misma

pueden tener distintos tiempo de vida, recordemos si una variable no es visible, no

necesariamente ha sido destruida. En cambio, si una variable fue destruida, esa

variable no es visible.

En el siguiente ejemplo se pueden observar todos los sitios donde se declaran las

variables, en ellas se puede observar conceptos como ámbito y alcance.

A continuación se muestra un ejemplo donde se pueden observar los conceptos

de ámbito y alcance de las variables.

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int a=0;

#include <stdio.h>

int numero1, numero2;

int funcion1(int numero1,int numero2){

}

int funcion2(void){

int numero1, numero2;

}

int funcion3(void){

int numero1, numero2;

if (numero1==numero2){

int numero1, numero2;

}

}

Variable Global

Parámetro Formal

Variable local

Variable Local (Bloque)

Page 23: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 23 de 89

void funcion1(int a){

printf("En funcion1 el valor de a:%d\n",a);

}

void funcion2(int p){

int a=p;

printf("En funcion2 el valor de a:%d\n",a);

funcion1(a+1);

}

int main(void){

int a=1;

printf("En main el valor de a:%d\n",a);

funcion2(a+1);

return 0;

}

/* --- Fin ejemplo --- */

Calificadores de acceso

Controlan las formas que se acceden o se modifican las variables.

const

No pueden ser modificadas por el programa, solo inicializar.

const int a=10;

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

void nocambiar(const char parametro){

printf("desde no cambiar p:%d\015",parametro);

}

int main(void){

const unsigned char b=0xFF;

nocambiar(b);

printf("%d\n",b);

return 0;

}

/* --- Fin ejemplo --- */

Page 24: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 24 de 89

volatile

El valor de una variable puede cambiar por medios no explícitamente

especificados por el programa.

Const volatile char *puerto = (const volatile char *) 0x30;

Calificadores de clase de almacenamiento

Indican al compilador como deben almacenar las variables.

extern

Específica (declara) que un objeto esta declarado con enlace externo en

otro módulo (archivo) del programa, es decir esta definido en otro archivo.

int x,y;

char c;

int main(){

x=123;

}

extern int x,y;

extern char c;

void func23(void){

y=10;

}

static

Cuando es variable local se crea un almacenamiento permanente, con

alcance en el bloque que es declarada y cuando la variable es global se

le indica que solo es conocida en el archivo que se declara.

int veces(void){

static cuentas=0;

cuentas++;

return cuentas;

}

static int cuentas=0;

int veces(void){

cuentas++;

return cuentas;

}

A continuación se muestra un ejemplo de compilado por separado, note

Page 25: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 25 de 89

que se trata de dos archivos, revise la documentación del compilador

para compilar y enlazar ambos modulos.

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*

* archivo: modulo1.c

*/

#include <stdio.h>

#include <stdlib.h>

extern int valor;

void funcion1(void);

int cuenta(void){

static int cuentas=0;

cuentas++;

return cuentas;

}

int main(void) {

funcion1();

printf("valor: %d\n",valor);

printf("cuentas: %d\n",cuenta());

printf("cuentas: %d\n",cuenta());

return EXIT_SUCCESS;

}

/* --- Fin archivo modulo1.c --- */

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*

* archivo: modulo2.c

*/

#include <stdio.h>

#include <stdlib.h>

int valor=5;

void funcion1(void){

printf("desde funcion1 valor: %d\n",valor);

}

/* --- Fin archivo modulo2.c --- */

Page 26: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 26 de 89

register

Se le pide al compilador que mantenga el valor en un registro del CPU en

lugar de la memoria, donde normalmente se almacenan las variables, esto

con el fin de realizar operaciones mucho más rápido.

Register int temp;

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(void){

register char c='a';

for(;c<='z';c++)

printf("%c",c);

return 0;

}

/* --- Fin ejemplo --- */

auto

Utilizado para declara variables locales, sin embargo todas las variables

que no son globales, se asumen auto.

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

void funcion1(void){

auto int a=1;

printf("En funcion1 el valor de a:%d\n",a);

a=a+1;

}

void funcion2(void){

static int a=1;

printf("En funcion2 el valor de a:%d\n",a);

a=a+1;

}

Page 27: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 27 de 89

int main(void){

funcion1();

funcion1();

funcion1();

funcion2();

funcion2();

funcion2();

return 0;

}

/* --- Fin ejemplo --- */

Page 28: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 28 de 89

Constantes

Refieren a valores fijos que no pueden ser modificados por el programa, también

se le conocen como literales, pueden ser de cualquier tipo básico de datos. La

forma que se representa cada constate depende de su tipo.

Enteras:

123

-123

012 /* en octal 10 */

0xA /* en hexadecimal 10 */

3500L /* long */

Reales:

123.45 /* float */

1001.2L /* long 28nión28 */

47e-4

.25E7

Caracteres:

'Z'

'\n' /* salto de línea */

'\r' /* retorno carro */

'\f' /* salto de página */

'\t' /* tabulador */

'\b' /* espacio atrás */

'\v' /* tabulador vertical */

'\\' /* barra invertida */

'\'' /* comillas simples */

'\”' /* comillas dobles */

'\Const' /* constante octal */

'\xConst' /* constante hexadecimal*/

Page 29: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 29 de 89

Cadenas de caracteres (string)

"HOLA MUNDO"

Una cadena de caracteres (string) es un vector de caracteres que

termina con un carácter '\0', hay siempre que recordar que Las

funciones que manipulan strings esperan que los mismos terminen en

'\0'.

Enumeradas

enum dias{Domingo, Lunes, Martes, Miercoles, Jueves,

Viernes, Sabado};

Page 30: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 30 de 89

Operadores y expresiones

El lenguaje C es sumamente rico en operadores incorporados, entre los que se

tienen:

Asignación

A diferencia de mucho otros lenguajes en C la asignación es un operador y

no una instrucción por lo cual se puede utilizar en cualquier expresión.

Lvalue = expresión

num=5

num=temp=0

Aritméticos

Negación - -x

Suma + x+y

Substracción - x-y

Multiplicación * x*y

División / x/y

Modulo % x%y

Relaciónales

Igual == x==y

Diferente ¡= x!=y

Mayor que > x>y

Mayor o igual que >= x>=y

Menor que < x<y

Menor o igual que <= x<=y

Lógicos

Negación ¡ ¡x

Y && x&&y (Evaluación en cortocircuito)

Page 31: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 31 de 89

O || x||y (Evaluación en cortocircuito)

Bits

Complemento ~ ~x (negación)

And & x&y

Or | x|y

Xor ^ x^y

Corrimiento der. >> x>>y

Corrimiento izq. << x<<y

Asignación Compuesta

x=x+y += x+=y

-= x-=y

*= x*=y

/= x/=y

%= x%=y

&= x&=y

|= x|=y

^= x^=y

>>= x>>=y

<<= x<<=y

Incrementales y decrementales

x=x+1 ++ x++

++x

x=x-1 -- x—

--x

Misceláneos

Condicional ¿: x?y:z

Dirección & &x

Indirección * *x

Page 32: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 32 de 89

Coma , x,y

Tamaño sizeof() sizeof(X)

Selector campo . x.y

Selector campo -> x->y equivale a (*x).y

Elemento arreglo [] x[y]

Conversión tipo (tipo) (tipo)x

Precedencia y Asociación de operadores

La siguiente tabla resume las reglas de precedencia y asociatividad de todos los

operadores, están colocados por orden de precedencia decreciente.

Precedencia Operador Asociatividad Nombre

MAYOR () [] -> . Izq. A Der.

¡ ~ ++ -- - (tipo) * & sizeof Der. A Izq. Unario

* / % Izq. A Der. Multiplicativo

+ - Izq. A Der. Aditivo

<< >> Izq. A Der. Corrimiento

< <= >= > Izq. A Der. Relacional

== ¡= Izq. A Der. Igualdad

& Izq. A Der. And bits

^ Izq. A Der. Xor bits

| Izq. A Der. 0r bits

&& Izq. A Der. And Lógico

|| Izq. A Der. Or Lógico

¿: Der. A Izq. Condicional

= += -= *= /= %= <<= >>= &= |= ^= Der. A Izq. Asignación

MENOR , Izq. A Der. Coma

Page 33: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 33 de 89

Evaluación en Cortocircuito

En relación con los operadores lógicos && y || son evaluados de izquierda a

derecha y la evaluación se detiene tan pronto se conoce el resultado ya seas

falso en los and (&&) y verdadero en los or (||), es decir se realiza una evaluación

en cortocircuito. La evaluación en cortocircuito podría tener efectos colaterales

sin embargo se pueden mencionar dos beneficios importantes:

Se considera una optimización ya que en la mayoría de los casos ahorra

bastante trabajo en la evaluación expresiones.

Una expresión relacional se puede utilizar para proteger una operación

potencialmente insegura en una segunda expresión, por ejemplo, en la

expresión (n != 0) && (x < 1 / n) nunca se podrá producir un error de división

entre 0 debido a que si por alguna razón n es igual a 0, el operando de la

izquierda (n!=0) se hace falsa y por lo tanto el operador de la izquierda no

se evalúa.

Muchos de los programas en C se basan en esa propiedad, por ejemplo

for(i=0;i<tamano && (c=getchar())!=EOF); i++)

buffer[i]=c;

Es decir antes de leer se verifica que hay espacio en el buffer.

A continuación se muestran varios programas que ejemplifican el uso de usos

de diferentes operadores:

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(void){

int i,j,k=0;

i=j=1;

printf("i:%d j:%d k:%d\n",i,j,k);

printf("i+=2:%d j-=1:%d \n",i+=2,j-=1);

i=j=1;

printf("i:%d j:%d \n",i,j);

Page 34: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 34 de 89

printf("i++:%d ++j:%d \n",i++,++j);

printf("i>2:%d j==2:%d !k:%d\n",i>2,j==2,!k);

printf("(i=5,3+4):%d\n",(i=5,3+4));

printf("(i=1,j=(i==1?i*i:i+i)):%d\n",(i=1,j=(i==1?i*i:i+i)));

printf("Cuidado\n");

i=j=1;

printf("i:%d j:%d \n",i,j);

printf("(i==1||i++):%d\n",(i==1||i++));

printf("(j!=1&&++j):%d\n",(j!=1&&++j));

printf("Evitar\n");

printf("i:%d j:%d \n",i,j);

printf("(i=1,i=2?i*i:i+i):%d\n",(i=1,i=2?i*i:i+i));

printf("i:%d j:%d \n",i,j);

i=j=1;

printf("i:%d j:%d \n",i,j);

printf("(i---j):%d\n",(i---j));

printf("i:%d j:%d \n",i,j);

i=5;

j=4;

printf("i:%d j:%d \n",i,j);

printf("(i>j?i:j):%d\n",(i>j?i:j));return 0;

}

/* --- Fin ejemplo --- */

Evaluación en cortocircuito

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(int argc,char **argv){

int n,r;

for(n=-10;n<=10;n++)

if(n!=0 && (r=100/n))

printf("%3d %4d\n",n,r);

return 0;

}

/* --- Fin del programa --- */

Trabajando con bits

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

Page 35: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 35 de 89

#define SET(B,S) (B|=1<<S)

#define CLEAR(B,S)(B&=~(1<<S))

#define GET(B,S)(B>>S&1)

int main(void){

unsigned char b=0;

printf("%d\n",b);

SET(b,0);

printf("%d\n",b);

SET(b,2);

printf("%d\n",b);

CLEAR(b,0);

printf("%d\n",b);

printf("Get 2: %d\n",GET(b,2));

CLEAR(b,2);

printf("Get 2: %d\n",GET(b,2));

printf("%d\n",b);

SET(b,5);

printf("%d\n",b);

return 0;

}

/* --- Fin ejemplo --- */

Otros usos interesantes de los operadores de bits

Determinar si un número es par

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(void){

int i;

printf("Ingrese un entero\n");

scanf("%d",&i);

printf("%d es %s\n",i,i&1?"Impar":"Par");

return 0;

}

/* --- Fin ejemplo --- */

Dividir entre dos un número entero

/*

* UCAB Guayana

Page 36: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 36 de 89

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(void){

int i;

printf("Ingrese un entero\n");

scanf("%d",&i);

printf("%d/2 %d\n",i,i>>1);

return 0;

}

/* --- Fin ejemplo --- */

Expresiones

Una expresión es una sucesión de operadores y operandos debidamente

relacionados, las expresiones combinan variables, constantes y llamadas a

funciones para producir nuevos valores, especificando los operadores lo que va a

ser realizado. Los operandos de diferente tipos que aparecen en una expresión se

convierten a un mismo tipo, tal cual como se especifica a continuación.

Conversión de tipo:

Implícita se realiza automáticamente por el compilador y a esta operación

se le denomina promoción:

En una asignación se convierte el tipo al lvalue.

En una expresión todos se convierte a un único tipo, usando el criterio de

convertirlos todos al tipo del mayor ―Tamaño‖

char o short int

unsigned char o unsigned short unsigned

int unsigned long unsigned long float double

Explicita: se realiza a través uso del operador cast, es decir la solicita

específicamente el programador:

c = '0' + (char)num;

Page 37: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 37 de 89

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(void){

int a=2,b=3;

float p;

p=(a+b)/2;

printf("%f\n",p);

p=(float)(a+b)/2;

printf("%f\n",p);

p=(a+b)/2.0;

printf("%f\n",p);

return 0;

}

/* --- Fin ejemplo --- */

Page 38: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 38 de 89

Instrucciones (sentencias ejecutables)

En sentido más general las instrucciones es una parte del programa que se puede

ejecutar, es decir, una instrucción (Sentencia o Proposición) especifica una

acción. En C las estructuras de control son sencillas (y familiares para

programadores que ya conozcan Pascal o cualquier otro lenguaje de

programación de alto nivel), permiten agrupar instrucciones, tomar decisiones (if-

else), seleccionar entre varias posibilidades (switch), hacer bucles (iteraciones)

evaluando la condición al empezar (while, for) o al acabar (do), etc.

En C hay cuatro tipos de instrucciones:

Las de expresión.

Las de bloques.

De etiqueta.

Las de control de flujo.

Instrucciones de expresión

Las instrucciones de expresión son aquellas en las que se especifica una expresión

válida seguida de un ―;‖.

A=5*6+8;

a+=b=1;

m=x>y?x:y;

Una instrucción de este tipo puede ser la llamada a una función seguida de ―;‖.

printf("Hello, world\n");

O la instrucción vacía

;

Instrucciones de bloques

Los bloques comienzan con una llave que abre y acaban con una llave que

cierra, conteniendo en su interior en primer lugar las posibles declaraciones

(locales al ámbito del bloque) y a continuación una lista de instrucciones.

Page 39: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 39 de 89

{

int i=0,j=1;

if(i && ++j)

printf("Entro\n");

printf("Valor de i:%d j:%d\n",i,j);

}

Observe que No hay ―;‖ luego de la ―}‖ que cierra el bloque.

En C99 se permite intercalar declaraciones e instrucciones dentro de un bloque.

{

int i;

i=2;

int j; // esta declaracion no es valida en C89

j=i*3;

printf("Los valores de i:%d y j:%d\n",i,j);

}

Instrucciones de etiqueta

La instrucción goto necesita de una etiqueta para operar, una etiqueta es un

identificador seguido de ―:‖ y pueda estar adherida a cualquier instrucción en la

misma función en la que está el goto, es decir el alcance de un goto es la función

y no se puede saltar entre funciones.

for(i=0;i<n;i++)

for(j=0;j<m;j++)

if(x[i]==y[j])

goto iguales;

...

iguales:

...

El código que involucra goto por lo general es mas difícil de entender y

mantener, adicionalmente se puede escribir códigos equivalentes sin él, aunque

tal vez con el precio adicional de variables extras y/o instrucciones de control

adicionales.

/*

* UCAB - Guayana

* Introduccion al Lenguaje C

Page 40: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 40 de 89

*/

#include <stdio.h>

#include <stdlib.h>

int main(void){

int i=0;

printf("Inicio\n");

while(1){

for(;;){

if(i==10) goto salir;

printf("\tValor i:%d\n",i);

i++;

}

}

salir:

printf("Fin\n");

return 0;

}

Instrucciones de control de flujo

Van a permitir controlar el flujo de la ejecución de instrucciones, es decir

especifican el orden en que se realiza el procesamiento, y se clasifican en:

Secuencia

Las de selección

Las de iteración

Las de salto

Secuencia

En C el ―;‖ es un terminador de instrucción no un separador como en otros

lenguajes como Pascal. En C las instrucciones se ejecutan una después de

la otra, en el orden en que están escritas, es decir, en secuencia.

m=x>y?x:y;

tasa = 0.15 * pago;

; /* instruccion vacia */

Selección

C contempla los if y el switch como instrucciones de selección.

if(exp)

instrucción

Page 41: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 41 de 89

En el if , si la expresión exp es verdadera se ejecuta la instrucción,

que puede ser una instrucción sencilla (incluyendo la vacía) o de

bloque.

if (estado == 'P')

tasa = 0.17 * pago;

if(exp)

instrucción (verdadero)

else

instrucción (falso)

En el if-else, si la expresión es verdadera se ejecuta la instrucción

(verdadero) en caso contrario se ejecuta la instrucción (falso).

if (estado == 'P')

tasa = 0.17 * pago;

else

tasa = 0.25 * pago;

Los if se pueden anidar, es decir if dentro de if, en C89 se especifican

al menos 15 niveles de anidamiento. En if anidados el else se asocia

con el if más próximo que ya no esté asociado.

switch(exp){

case valor:

instrucciones

case valor:

instrucciones

[default:

instrucciones]

}

El switch es una instrucción de selección múltiple, que compara el

resultado de una expresión exp con una lista de valores (enteros o

Page 42: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 42 de 89

de carácter) especificada por los case en orden, cuando se

encuentra la correspondencia se ejecutan las instrucciones

asociadas con ese case, hasta que se encuentra un break o se llega

a la ultima instrucción del switch. Las instrucciones asociadas al

default (el cual es opcional) se ejecutan si no se ha encontrado

ninguna correspondencia.

/* Ejemplo: Imprime un color segun su codigo */

char color;

switch (color) {

case 'a':

case 'A': printf("AMARILLO\n");

break;

case 'r':

case 'R': printf("ROJO\n");

break;

case 'v':

case 'V': printf("VERDE\n");

break;

case 'b':

case 'B': printf("BLANCO\n");

break;

default: printf("CODIGO DESCONOCIDO\n");

}

Se pueden tener un switch formando parte de la secuencia de

instrucciones de otro switch.

Iteración

Las instrucciones de iteración (bucles) permiten ejecutar una instrucción o

un conjunto de ellas, mientras se cumpla una determinada condición. C

contempla tres instrucciones de iteración: while, do-while y for.

while (exp)

instrucción

En el while, la instrucción se ejecuta mientras la expresión sea

verdadera.

/* Ejemplo: Calculo de la media de un vector */

int vector[100], i = 0, media, suma = 0;

while (i < 100)

suma += vector [i++];

Page 43: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 43 de 89

media = suma / 100;

do

instrucción

while(exp);

En el do-while la instrucción se ejecuta mientras la expresión sea

verdadera, a diferencia del while, que analiza la condición del bucle

al principio, el bucle do-while comprueba la condición al final. Esto

significa que las instrucciones se ejecuta al menos una vez.

/* Ejemplo: Calculo de la media de un vector */

int vector[100], i, media, suma = 0;

i = 0;

do

suma += vector [i++];

while (i < 100);

media = suma / 100;

Aunque sea una sola instrucción, con frecuencia se colocan entre

llaves ―{‖ y ―}‖ por legibilidad del código.

int vector[100];

int main(void){

int i=0, media, suma = 0;

do{

suma += vector [i++];

}while (i < 100);

media = suma / 100;

return 0;

}

for(exp1;exp2;exp3)

instrucción

La instrucción for equivale directamente a lo siguiente:

exp1;

while (exp2) {

instrucción

exp3;

}

Page 44: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 44 de 89

/* Ejemplo: Calculo de la media de un vector */

int v[100], i, media, suma = 0;

for (i = 0; i < 100; i++)

suma += v[i];

media = suma / 100;

Dos casos interesantes del for puede ser bucles infinitos (aunque se

puede hacer con otras instrucciones)

for (;;){

...

/* un bucle infinito */

...

}

Y los sin cuerpos for (i=0;i<5;i++); /* bucle sin cuerpo */

Saltos

C tiene cuatro instrucciones de salto incondicional: return, continue, break

y goto. Las instrucciones de return y goto se pueden utilizar en cualquier

parte de una función, mientas las instrucciones continue y break se utilizan

junto a instrucciones de iteración, Adicionalmente ya se estudio el uso del

break en los switch.

return [exp];

Retorna de una función, hace que la ejecución vuelva a punto en

que se realizó la llamada, cuando se acompaña de una expresión,

el valor de la expresión es el valor de vuelta de la función. Un return

sin expresión se utiliza para retornar de las funciones tipo void.

Continue;

Solo puede aparecer dentro de una instrucción de iteración y fuerza

una nueva iteración (a verificar la condición) del ciclo más anidado

que encierra la instrucción.

break ;

Page 45: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 45 de 89

Cuando esta dentro de una instrucción de iteración fuerza la

terminación inmediata del ciclo más anidado que encierra la

instrucción, pasando el control a la instrucción siguiente a la

terminada. Como se menciono anteriormente ya se estudio el uso

del break en los switch.

goto etiqueta;

Salta a una etiqueta dentro de la misma función, transfiriéndose el

control a la instrucción etiquetada.

exit(int)

Aunque no es una instrucción de control es una función de la

biblioteca estándar que termina la ejecución del programa cuando

se le llama, el argumento de exit está disponible para proceso de

llamada (se usa 0 para indicar la terminación normal del programa)

se tienen definido las siguientes macros EXIT_SUCESS y EXIT_FAILURE

como códigos de vueltas. La función exit requiere la inclusión del

archivo de cabecera <stdio.h>

A continuación se muestra estructuras de control de flujo, destaca el uso del

operador , (coma) en el for y la instrucción break en el while:

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(void){

int i,j;

for(i=0,j=10;i<j;i++,j--)

printf("for: %d - %d\n",i,j);

j=0,i=10;

while(1)

if(i==5)

Page 46: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 46 de 89

break;

else

printf("while: %d\n",i--);

do

printf("do-while:%d\n",j);

while(j!=0);

}

/* --- Fin ejemplo --- */

Ahora se destaca el uso de la instrucción continue:

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(void){

int i=0,j=100,k;

while(i<j){

printf("%d-%d\n",i,j);

i+=5;

j-=5;

if((k=j-i)>50){

printf("%d\n",k);

continue;

}

i+=5;

j-=5;

}

return 0;

}

/* --- Fin ejemplo --- */

Ahora se observa el uso de la instrucción return y la función exit

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

#include <stdlib.h>

void funcion(int opcion){

switch (opcion) {

case 1:

Page 47: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 47 de 89

break;

case 2:

printf("Retornar al medio de la funcion\n");

return;

case 3:

printf("Salir del programa aqui\n");

exit(EXIT_FAILURE);

}

printf("Retornar por final de la funcion\n");

}

void siempre(void){

printf("Por aqui siempre paso\n");

}

int main(void){

atexit(siempre);

funcion(1);

funcion(2);

funcion(3);

printf("por aqui nunca paso\n");

exit(EXIT_SUCCESS);

}

/* --- Fin ejemplo --- */

Page 48: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 48 de 89

Funciones y parámetros

El lenguaje C sólo permite funciones, no hay procedimientos. La forma de

declarar las funciones es la siguiente:

<tipo> identificador(lista parámetros formales){

declaraciones

enunciados

}

Donde tipo es el tipo del dato que devuelve la función, que si no aparece se

asume siempre del tipo int y nombre es el identificador de la función.

La forma de invocar a una función es similar a otros lenguajes, pero aunque la

función no tenga parámetros se deben colocar los paréntesis. Por otra parte, es

lícito no realizar ninguna acción con el resultado que devuelve una función, pero

en ese caso debiera ponerse un type cast (void) en la llamada.

Las listas de parámetros formales y de parámetros reales no tienen por qué

coincidir en número, e incluso en tipo. Para evitar este problema se puede

declarar el prototipo de la función antes de invocarla. La forma de escribir el

prototipo de una función es la siguiente:

<tipo> identificador (<tipo parámetro_1>, … <tipo parámetro_N>);

Sólo existe paso de parámetros por valor excepto los arreglos que pasan por

referencia.

Para terminar la ejecución de una función se usa la sentencia return. Su sintaxis es:

return [expresión];

Donde la expresión es el valor que retorna la función y debe ser del mismo tipo

que el de la función.

/*

* UCAB Guayana

Page 49: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 49 de 89

* Introduccion al Lenguaje C

*/

#include <stdio.h>

#include <stdlib.h>

/* Ejemplo: Búsqueda binaria */

int busqueda_binaria(int elemento,int vector[], int tamano){

int bajo=0,alto=tamano-1,central,valor;

while(bajo<=alto){

central=(alto+bajo)/2;

valor=vector[central];

if(elemento==valor)

return central;

if(elemento < valor)

alto=central-1;

else

bajo=central+1;

}

return -1;

}

int main(void){

int valores[10]={1,5,8,9,10,23,25,30,40,50};

int elemento=12;

printf("Posición de %d es %d\n",elemento,

busqueda_binaria(elemento,valores,10));

exit(EXIT_SUCCESS);

}

/* --- Fin ejemplo --- */

C soporta el llamado recursivo de una función, es decir una función que se llame

a sí misma. La recursión es el proceso de definir algo en términos de sí mismo.

El siguiente programa resuelve el clásico problema de las torres de Hanói:

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

void hanoi(int n,char desde,char hasta,char usando){

if(n==1){

printf("%c --> %c\n",desde,hasta);

return;

}

Page 50: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 50 de 89

hanoi(n-1,desde,usando,hasta);

printf("%c --> %c\n",desde,hasta);

hanoi(n-1,usando,hasta,desde);

}

int main(void){

hanoi(3,'A','B','C');

return 0;

}

/* --- Fin ejemplo --- */

Ahora se puede observar usando el valor de retorno de la función, para mostrar la

cantidad de movimientos realizados:

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int hanoi(int n,char desde,char hasta,char usando){

int m;

if(n==1){

printf("%c --> %c\n",desde,hasta);

return 1;

}

m=hanoi(n-1,desde,usando,hasta);

printf("%c --> %c\n",desde,hasta);

m+=hanoi(n-1,usando,hasta,desde);

return m+1;

}

int main(void){

printf("movimientos:%d\n",hanoi(3,'A','B','C'));

return 0;

}

/* --- Fin ejemplo --- */

Las funciones pueden devolver valores de los tipos básicos o de los estructurados,

en las funciones que no retornen nada (procedimiento) el tipo devuelto se

declara como void. Así mismo, cuando no exista ningún parámetro formal, se

deben poner simplemente los dos paréntesis ( ) o (void).

/*

Page 51: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 51 de 89

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

struct punto{

int x,y;

} p1;

/* funcion minima */

nada(){}

void saludo(void){

printf("Operaciones con puntos\n");

}

void imprime(struct punto p){

printf("punto: %d,%d\n",p.x,p.y);

}

struct punto suma(struct punto p1, struct punto p2){

struct punto t;

t.x = p1.x + p2.x;

t.y = p1.y + p2.y;

return t;

}

int main(int argc,char **argv){

struct punto p1 = {1,2},p2;

saludo();

imprime(p1);

p2=p1;

imprime(p2);

p2=suma(p1,p2);

imprime(p2);

nada();

return 0;

}

/* --- Fin del programa --- */

Page 52: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 52 de 89

Arreglos, Estructuras, Uniones y Enumeraciones

El lenguaje C proporciona varias formas para la creación de tipos de datos, ya

sean simples o compuestos, a partir de los tipos ya definidos.

Arreglos: Colección de variables del mismo tipo que se referencia por un

nombre en común, y un elemento especifico se accede mediante un

índice colocando el nombre de arreglo seguido del índice entre corchetes.

En C los arreglos tiene como 0 como el índice para su primer elemento.

Declaración:

tipo identificado[tamaño];

double balance[100];

Acceso al primer elemento:

balance[0] = 123.5;

C permite arreglos de más de una dimensión (multidimensionales), siendo

su forma de declaración la siguiente:

tipo identificador [tamaño1] [tamaño2]… [tamañoN]

Se puede observar que en la declaración cada dimensión se coloca en sus

corchetes, de igual forma se procede para acceder a un elemento en

particular. C permite inicializar los arreglos durante la inicialización con una

lista de elementos separados por coma encerados entre llaves. Se puede

hacer que el compilador calcule la dimensión de los arreglos para

mantener a todos los elementos de la inicialización, a esto se le denomina

arreglos no delimitados, donde no se especifica la dimensión.

char tablero[8][8];

int numero[]={1,2,4,3,9};

int i,cuad[5][2]={{1,1},{2,4},{3,9},{4,16},{5,25}};

for(i=0;i<5;i++)

printf("el cuadrado de %d es %d\n",cuad[i][0],cuad[i][1]);

En arreglos bidimensionales, se almacenan por filas y columnas (donde el

Page 53: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 53 de 89

primer índice indica las filas y el segundo las columnas) es decir que el

índice más a la derecha cambia más rápido que el de más a la izquierda

cuando se recorren los elementos en la memoria.

En C89 se deben declarar las dimensiones de los arreglos con dimensiones

constantes, sin embargo C99 permite la declaración de arreglos locales de

longitud variables.

int vector(int n){ // en C99 arreglos de longitud variable

int i,vector[n];

for(i=0;i<n;i

vector[i]=i;

return i;

}

Estructuras: Agrupación de miembros diferentes que se referencian bajo un

único nombre.

Struct datos_persona{

unsigned int codigo;

char nombre[30];

char apellido[30];

char sexo;

};

Los elementos que forman parte de una estructura se denomina miembros

(elementos o campos). La palara struct indica al compilador que se está

declarando un nuevo tipo, para declarar una o varias variables del tipo

añadido se puede hacer de de la siguiente forma:

struct datos_persona persona;

O se puede declarar una o más variables a la vez que se declarar la

estructura, como muestra el ejemplo:

struct datos_persona {

unsigned int codigo;

char nombre[30];

char apellido[30];

char sexo;

} persona;

Page 54: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 54 de 89

O si solo se necesitan las variables de la estructura, no se requiere el nombre

de la estructura:

struct {

unsigned int codigo;

char nombre[30];

char apellido[30];

char sexo;

} persona;

Las únicas operaciones permitidas sobre una estructura son asignarla, tomar

su dirección con &, tener acceso a sus miembros, pasarla como

argumentos a funciones y también regresarlas de funciones. Las estructuras

no se pueden comparar. Las estructuras se pueden inicializar con una lista

de variables constantes y una estructura automática también se puede

inicializar con una asignación.

El acceso a los miembros de una estructura se realizar con el operador .

(Punto) por ejemplo:

persona.sexo = ‘F’;

A través de una única asignación, se puede asignar el contenido de una

estructura a otra, no es necesaria la asignación de cada miembro por

separado.

Cuando se pasa una estructura a una función como un parámetro

realmente se pasa por valor la estructura completa.

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

struct punto{

int x,y;

} p1;

void imprime(struct punto p){

printf("punto: %d,%d\n",p.x,p.y);

}

Page 55: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 55 de 89

struct punto suma(struct punto p1, struct punto p2){

struct punto t=p2;

t.x += p1.x;

t.y += p1.y;

return t;

}

int main(int argc,char **argv){

struct punto p1 = {1,2},p2;

imprime(p1);

p2=p1;

imprime(p2);

p2=suma(p1,p2);

imprime(p2);

return 0;

}

/* --- Fin del programa --- */

Uniones: Permite que una misma parte de la memoria sea definida como

dos o más tipos.

Union numero{

int entero;

float real;

}

Cuando una variable se declara como una union el compilador reserva

espacio para el mayor de los miembros. Pos su naturaleza las uniones

proporciona un mecanismo para interpretar una secuencia de bits de

diferentes formas. Y su declaración y uso es similar a las estructuras.

Campo Bits: tipo especial de estructura o unión que permite el fácil acceso

a bits individuales. Se declaran de la siguiente forma:

tipo nombre: longitud;

Y no es necesario nombrarlos, por ejemplo:

Struct estado{

unsigned: 4;

unsigned cts:1;

unsigned drs:1;

}

Page 56: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 56 de 89

Enumeraciones: Una lista de constantes enteros con nombres.

La declaración tendrá la siguiente forma:

enum nombre { lista_de_enumeracion } ;

Ejemplo:

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

enum dias{Domingo, Lunes, Martes, Miercoles, Jueves, Viernes,

Sabado};

int main(int argc,char **argv){

enum dias dia;

for(dia=Domingo;dia<=Sabado;dia++){

printf("%d\n",dia);

}

return 0;

}

/* --- Fin del programa --- */

En una enumeración cada una de los elementos se corresponde con un

valor entero, donde el primero se corresponde con el cero y los siguientes

se incrementan en uno sucesivamente, aunque se pueden definir otros

valores utilizando un inicializador (el signo de igualdad seguido de un valor

entero) a los elementos que siguen a uno inicializado se les hace

corresponder el valor previo incrementado en uno sucesivamente.

Como los elementos se corresponden con constantes enteras se puede

usarse en cualquier expresión entera.

Ejemplo usando estructuras y uniones:

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

Page 57: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 57 de 89

#include <stdio.h>

typedef unsigned int PALABRA;

typedef struct{

unsigned a:1;

unsigned b:1;

unsigned :4;

unsigned c:1;

unsigned d:1;

} SBITS;

typedef union{

PALABRA palabra;

SBITS bits;

}AMBOS;

int main(void){

AMBOS a;

a.palabra=0;

printf("Sizeof Palabra%d\n",sizeof(PALABRA));

printf("Sizeof SBITS%d\n",sizeof(SBITS));

printf("Sizeof UNION%d\n",sizeof(AMBOS));

printf("%d\n",a.palabra);

a.bits.c=1;

printf("%d\n",a.palabra);

return 0;

}

/* --- Fin ejemplo --- */

Ahora un ejemplo con arreglos:

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int buscar(int e,int a[],int t){

register int i;

for(i=0;i<t;i++)

if(a[i]==e)

return i;

return -1;

}

int main(void){

int a[]={2,3,6,8,10,12,23,15,22,1,9,7};

printf("Buscar 12:%d\n",buscar(12,a,12));

printf("Buscar 25:%d\n",buscar(25,a,12));

return 0;

Page 58: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 58 de 89

}

/* --- Fin ejemplo --- */

Page 59: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 59 de 89

Apuntadores

Los apuntadores son una de las características más útiles y a la vez más peligrosas

de que dispone el lenguaje C. En C se permite declarar una variable que

contiene la dirección de otra variable, o sea, un apuntador. Cuando se declara

un apuntador éste contiene una dirección arbitraria, si leemos a dónde apunta

nos dará un valor indefinido y si se escribe en tal dirección estamos variando el

contenido de una posición de memoria que no conocemos por lo que podemos

hacer que el sistema tenga comportamientos no deseados, por lo que antes de

hacer uso de un puntero debemos asignarle una dirección de memoria en

nuestro espacio de trabajo.

La forma de declarar un apuntador es la siguiente:

tipo *nombre;

Por ejemplo la declaración:

int i, *p=&i;

Se muestra gráficamente:

El tipo indica al tipo de datos a los que apuntará el apuntador, pero como efecto

de la declaración se reservará espacio en memoria para guardar un apuntador,

no para el tipo de datos al que apunta es decir la declaración de un apuntador

no lleva asociada la reserva de espacio para el tipo de datos apuntado.

Existe un carácter especial que se usa como prefijo y aplicado a las variables

indica la dirección de memoria que ocupa la variable, no el contenido (valor).

Este símbolo es &. Además existe otro prefijo, *, que aplicado a una variable de

tipo puntero indica el contenido de la dirección a la que apunta dicho

apuntador. A estos dos símbolos se les llama dirección e indirección (contenido)

respectivamente.

Page 60: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 60 de 89

A los apuntadores se les puede añadir o restar una cierta cantidad entera.

Admiten comparaciones e incrementos y decrementos. Cuando un apuntador es

incrementado en uno pasa a apuntar al siguiente elemento del arreglo al que

apuntaba, no al siguiente byte, es decir, se incrementa en el número de bytes

que ocupa el tipo al que apunta. También se permite restar dos punteros para

calcular la distancia entre ellos.

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(void){

int i,*ip;

i=0;

ip=&i;

*ip=5;

printf("i:%d\n",i);

return 0;

}

/* --- Fin ejemplo --- */

Un buen ejemplo para aritmética de apuntadores de la función que

calcula la longitud de una cadena de caracteres (string).

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

#include <malloc.h>

char *ms = "HOLA MUNDO";

int mystrlen(const char *s){

const char *p = s;

while(*p)

p++;

return p-s;

}

int main(void){

Page 61: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 61 de 89

printf("ms:%s\n",ms);

printf("Longitud ms:%d\n",mystrlen(ms));

return 0;

}

/* --- Fin ejemplo --- */

Apuntadores a apuntadores

Se puede hacer un apuntador que apunte a otro apuntador que apunte a una

variable. Esta situación se denomina apuntador de apuntador o indirección

múltiples. Esta situación puede llevarse a la extensión que se desee por ejemplo

un apuntador a un apuntador a un apuntador, pero son pocos los casos que lo

requieran más allá de un apuntador a un apuntador, La indirección múltiple en

exceso puede resultar difícil de seguir y puede ser propensa a errores.

Por ejemplo la siguiente declaración:

int i=10 *p=&i, *pp=&p;

Se representa gráficamente:

Como se puede observar en la figura en el caso de un apuntador a un

apuntador, el primer apuntador contiene la dirección del segundo apuntador,

que apunta a la variable que contiene el valor deseado.

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(int argc,char **argv){

int i=5,j=10,*p=&i,**pp=&p;

printf("valor de *p:%d\n", *p);

printf("valor de **pp:%d\n", **pp);

p=&j; /* No se cambia pp pero ... */

printf("valor de **pp:%d\n", **pp);

return 0;

Page 62: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 62 de 89

}

/* --- Fin del programa --- */

Un arreglo de apuntadores es un caso particular de apuntadores a apuntadores.

Relación entre apuntadores y arreglos

Los apuntadores y los arreglos en C están relacionados íntimamente y puede ser

utilizado casi en forma indistinta. Un nombre de arreglo puede considerarse como

un apuntador, los apuntadores pueden utilizarse para realizar cualquier operación

que involucre arreglos.

Por ejemplo si se declara un arreglo de enteros int ia[5]; y un apuntador a

entero int *iap; Dado que el nombre del arreglo si elemento es un apuntador

al primer elemento se hacer al apuntador igual a la dirección del primer elemento

iap=ia; (o más extraño iap=&ia[0];) alternativamente el elemento ia[3]

puede ser referenciado como *(ia+3)

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(int argc,char *argv[]){

int *iap, ia[5]={0,1,2,3,4};

iap=ia;

printf("ia[3]:%d\n",ia[3]);

printf("*(iap+3):%d\n",*(iap+3));

printf("*(3+iap):%d\n",*(3+ia));

printf("3[ia]:%d\n",3[ia]);

return 0;

}

/* --- Fin ejemplo --- */

Un NO buen ejemplo:

/*

* UCAB Guayana

Page 63: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 63 de 89

* Introduccion al Lenguaje C

*/

#include <stdio.h>

#define MAX 12

int a[MAX]={11,7,6,5,4,3,1,0},

b[MAX]={10,9,8,4,3,2,0},

c[2*MAX-1]={0};

void imprime(const int *x){

for(;*x;x++)

printf("%d ",*x);

printf("\n");

}

void merge(const int *f1,const int *f2,int *d){

while(*d++=*f1>*f2?*f1++:*f2++);

}

int main(void){

imprime(a);

imprime(b);

merge(b,a,c);

imprime(c);

return 0;

}

/* --- Fin ejemplo --- */

Puede resultar difícil de leer la función merge y si se detalla se puede observar

que no es del todo eficiente.

El siguiente ejemplo se evidencia la diferencian de usar arreglos y apuntadores,

en la manipulación de cadenas de caracteres (string), en nuestro caso en

particular la copia de una cadena de caracteres.

Empezamos implementado la función mystrcpy con arreglos.

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

char A[] = "HOLA MUNDO",B[12];

void mystrcpy(char d[],char f[]){

register int i;

Page 64: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 64 de 89

i=0;

while((d[i]=f[i])!='\0')

i++;

}

int main(void){

printf("A:%s\n",A);

mystrcpy(B,A);

printf("B:%s\n",B);

return 0;

}

/* --- Fin ejemplo --- */

Ahora con apuntadores, razone las ventajas de esta aproximación.

void mystrcpy(char *d,const char *f){

while((*d=*f)!='\0'){

d++;

f++;

}

}

Ahora un poco más eficiente, utilizando apuntadores.

void mystrcpy(char *d,const char *f){

while(*d++=*f++);

}

Aunque nos pueda parecer poco legible al principio, es importante

acostumbrase a este estilo de programación puesto que el que se

consigue con frecuencia en aplicaciones y ejemplos.

Como utilizar el calificador const con apuntadores

El calificador const permite informarle al compilador que el valor de una variable

en particular no deberá ser modificado. Existen cuatro formas de declara o pasar

un apuntador a una función:

Un apuntador no constante a datos no constantes

char *s

Un apuntador no constante a datos constantes

Page 65: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 65 de 89

const char *s

Un apuntador constante a datos no constantes

int * const ip

o

int i;

int * const ip=&i;

Un apuntador constante a datos constantes

const int * const ip

O

int i=5;

const int * const ip=&i;

Ejemplo intento de modificación de datos a través de un apuntador no constante

a datos constantes

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(void){

int i=5;

const int *ip=&i;

*ip=2; /* operacion invalida */

printf("%d",*ip);

return 0;

}

/* --- Fin ejemplo --- */

Arreglos de apuntadores

Al igual que de cualquier otro tipo de dato se permite declarar un array de

punteros. La forma de hacerlo es:

Page 66: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 66 de 89

tipo *nombre[expresion1][expresion2]…;

int *iap[5];

float *afp[];

void (*funciones[3])()={funcion1,funcion2,funcion3};

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

void print_error(const int num){

static char *err[]={

"Error numero cero",

"Error numero uno",

"Error numero dos",

"Error numero tres"

};

printf("Error (%d):%s\n",num,err[num]);

}

int main(void){

print_error(2);

return 0;

}

/* --- Fin ejemplo --- */

Arreglo de apuntadores vs. arreglos multidimensionales

Analicemos el siguiente programa

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

char *cpa[]={"Esta"," es"," una"," Prueba"};

char cba[][8]={"Esta"," es"," una"," Prueba"};

int main(void){

printf("sizeof(char *cpa[]):%d\n",sizeof(cpa));

printf("sizeof(char cba[][8]):%d\n",sizeof(cba));

printf("por la dudas %c es %c\n",cpa[3][1],cba[3][1]);

printf("*cpa[2]:%s\n",cpa[2]);

printf("cba[2]:%s\n",cba[2]);

return 0;

Page 67: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 67 de 89

}

/* --- Fin ejemplo --- */

Para cba , al ser un arreglo bidimensional, se reserva 4x8 sizeof(char) ahora para

cpa, al ser un arreglo de apuntadores a caracteres, se reserva 4xsizeof(char *). En

el caso en que cpa apunte a elementos de 8 sizeof(char) entonces se tiene 4x8x

sizeof(char) + 4xsizeof(char *). Ahora la ventaja del arreglo de apuntadores es que

los reglones pueden ser de longitudes diferentes.

Apuntadores a estructuras

Existe una pequeña variación a la hora de acceder a una estructura mediante un

apuntador, por ejemplo, (*p).miembro se puede escribir como p->miembro.

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

struct campos{

char campo1;

int campo2;

int campo3[4];

} e, *ep, ea[4];

int main(void){

e.campo1='a';

e.campo2=25;

Page 68: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 68 de 89

ep=&e;

printf("campo1:%c\n",(*ep).campo1);

printf("campo2:%d\n",ep->campo2);

ea[2].campo3[1]=123;

printf("ea[2].campo3[1]:%d\n",ea[2].campo3[1]);

return 0;

}

/* --- Fin ejemplo --- */

Pase de apuntadores a funciones

El lenguaje C sólo admite paso de parámetros por valor, pero tiene una forma de

simular un paso por referencia (variable), pasando un apuntador que es la

dirección donde están los datos (p. ej. &v). En realidad se pasa un valor que es

una dirección de una variable.

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

void intercambia1(int x,int y){

int z;

z=x;

x=y;

y=z;

}

void intercambia2(int *x,int *y){

int z;

z=*x;

*x=*y;

*y=z;

}

int main(void){

int a=2,b=3;

printf("a:%d b:%d\n",a,b);

intercambia1(a,b);

printf("a:%d b:%d\n",a,b);

intercambia2(&a,&b);

printf("a:%d b:%d\n",a,b);

Page 69: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 69 de 89

return 0;

}

/* --- Fin ejemplo --- */

Apuntadores a funciones

Es posible crear apuntadores que apunten a funciones, en lugar de datos los

apuntadores a funciones apuntan a código ejecutable. Los apuntadores a

función permiten pasar a una función como argumento a otra función.

Un ejemplo de arreglo de funciones:

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

void funcion1(){

printf("Funcion 1\n");

}

void funcion2(){

printf("Funcion 2\n");

}

void funcion3(){

printf("Funcion 3\n");

}

int main(void){

void (*funciones[3])()={funcion1,funcion2,funcion3};

int opcion;

printf("Opcion (1-3) => ");

scanf("%d",&opcion);

if(opcion>=1 && opcion <=3)

(*funciones[opcion-1])();

else

printf("Error en opcion\n");

return 0;

}

/* --- Fin ejemplo --- */

Page 70: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 70 de 89

Paso de una función como argumento a otra función:

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

void funcion1(){

printf("Funcion 1\n");

}

void funcion2(){

printf("Funcion 2\n");

}

void funcion3(){

printf("Funcion 3\n");

}

void llamar_opciones(void (*funcion)()){

printf("Llamar opciones:");

(*funcion)();

}

int main(void){

void (*funciones[3])()={funcion1,funcion2,funcion3};

int opcion;

printf("Opcion (1-3) => ");

scanf("%d",&opcion);

if(opcion>=1 && opcion <=3)

llamar_opciones(funciones[opcion-1]);

else

printf("Error en opcion\n");

return 0;

}

/* --- Fin ejemplo --- */

Page 71: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 71 de 89

La biblioteca estándar

En el lenguaje C toda la entrada y salida de un programa se realiza a través de

funciones definidas en Bibliotecas. También se encuentran definidas en

bibliotecas otros tipos de funciones. Dichas bibliotecas, o la mayoría, son estándar

(las funciones en ellas definidas tienen nombres estándar) lo que facilita la

portabilidad de los programas. Al inicio de cada archivo se debe indicar las

declaraciones de las bibliotecas que se utilizarán. Esto se realiza utilizando la

directiva #include, cuya sintaxis es:

#include nombre_archivo

Donde nombre_archivo es el archivo de encabezado, donde se realizan las

definiciones de la bibliotecas, se coloca entre signos de menor y mayor

(<nombre_archivo>) o entre comillas dobles ("nombre_archivo") según el lugar en

que haya que buscar el archivo ya sea en los directorios asignados por defecto a

los archivos ―incluye‖ o en el actual.

Estos archivos de definiciones suelen tener la extensión .h (de header, cabeceras)

y contienen definiciones necesarias para la utilización de las funciones contenidas

en la biblioteca.

Por ejemplo:

#include <stdio.h>

Incluye la cabecera para usar la biblioteca de entrada/salida desde el directorio

estándar

#include "stdio.h"

Igual al anterior pero las busca en el directorio actual

#include "c:\proyecto\colas.h"

Incluye el archivo colas.h del directorio proyecto

Algunas librerías estándares importantes en ANSI C:

conio.h Soporte para I/O por consola y puertos.

Page 72: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 72 de 89

ctype.h Manejo de caracteres.

errno.h Informes de error.

float.h Valores de flotantes dependiente de la implementación.

io.h Entrada y salida a bajo nivel.

malloc.h Soporte para las funciones para obtener y liberar memoria.

math.h Conjunto de funciones matemáticas.

setjmp.h Soporte para saltos no locales

signal.h Soporte para el manejo de señales.

stdarg Soporte para lista de argumentos de longitud variable.

stdio.h Entrada y salida estándar.

stdlib.h Conjunto de funciones estándar, p.e. conversión de tipos.

string.h Funciones de manejo de cadenas.

time.h soporte para las funciones de tiempo del sistema

Adicionalmente dependiendo del Sistema de Operación se puede encontrar

biblioteca para el llamado a las primitivas del Sistema de Operación, en el caso

de UNIX, se tiene entre otras:

signal.h para el manejo de señales del sistema

sys/sem.h para el manejo de semáforos

sys/shm.h manipulación de memoria compartida

sys/socket manejo de manejo de socket

A continuación se muestra el uso de biblioteca <setjmp.h> para saltos no locales

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

#include <setjmp.h>

jmp_buf env;

void funcion4(void){

printf("Primera de Funcion4\n");

longjmp(env,1);

printf("Segunda de Funcion4\n");

Page 73: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 73 de 89

}

void funcion3(void){

printf("Primera de Funcion3\n");

funcion4();

printf("Segunda de Funcion3\n");

}

void funcion2(void){

printf("Primera de Funcion2\n");

funcion3();

printf("Segunda de Funcion3\n");

}

void funcion1(void){

printf("Primera de Funcion1\n");

funcion2();

printf("Segunda de Funcion1\n");

}

int main(void){

if(setjmp(env)==0){

printf("Ahora vamos a llamar las funciones\n");

funcion1();

}

else

printf("Regresamos con \"un salto no local\"\n");

printf("Ahora si salimos\n");

return 0;

}

/* --- Fin ejemplo --- */

Page 74: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 74 de 89

Entrada y Salida

Los principales archivos estándar definidos en toda aplicación en C son:

stdin (entrada estándar, asociado al teclado)

stdout (salida estándar, asociado a la pantalla)

stderr (error estándar, asociado a la pantalla)

Las principales funciones de entrada y salida son:

putchar(char c) Función de salida de carácter. Imprime el carácter c por

la salida estándar.

char getchar(void) Entrada estándar de carácter. Obtiene un carácter de

la entrada estándar y este es el valor que devuelve la función.

int printf(const char *format, ...) Imprime por la salida estándar una

secuencia de caracteres cuya estructura está definida en la string format.

Se permite dar salida a cualquier tipo de dato predefinido. La string format

tiene la estructura de una string normal pero admite además caracteres de

conversión (%) para indicar qué tipo de dato se ha de imprimir.

La estructura de una cadena de formato es:

%[flags][.width][.prec][F|N|h|l]type

donde type es un caracter de conversión. El campo flag afecta al tipo de

justificación; width a la anchura utilizada para imprimir; .prec a la precisión

a la hora de escribir números en coma flotante. El último campo opcional

afecta a la interpretación del argumento.

%c Carácter

%d Entero decimal

%e Flotante se representa con exponente

%f Flotante se representa sin exponente

%g Menor entre %e y %f

%o Entero octal, sin el cero inicial

%u Entero decimal sin signo

%x Entero representado en hexa sin 0x

%s Strings (cadenas)

Page 75: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 75 de 89

int scanf(const char *format, ...) Es el equivalente a printf para la entrada

estándar de datos de forma estructurada. En la cadena de formato se

pueden poner todos los caracteres de conversión (%) de la tabla anterior.

Además admite %[cadena], donde se acepta cualquier cadena formada

por elementos pertenecientes a cadena, o si la cadena comienza con '^',

los no pertenecientes y %*c carácter de supresión de asignación.

FILE *fopen(const char *filename,const char *mode) Abre un fichero en alto

nivel. filename es el nombre del fichero y mode indica el modo de apertura

del fichero. Retorna un puntero al descriptor del fichero (FILE).

"r" Abrir un archivo existente solo para lectura

"w" Abrir un archivo solo para escritura

"a" Abrir un archivo para añadir. Si no existe se crea uno

"r+" Abrir un archivo existente para lectura y escritura

"w+" Abrir un archivo nuevo para lectura y escritura

"a+" Abrir un archivo nuevo para leer y añadir

int fclose(FILE *fp) Cierra un fichero cuyo puntero al descriptor es fp.

int fprintf(FILE *fp,const char *format, ...) Escribe en el fichero descrito por fp

datos con el formato indicado por format.

int fscanf(FILE *fp,const char *format, ...) Lee del fichero descrito por fp.

Tanto esta llamada como la anterior son las equivalentes de printf y scanf

que operan sobre ficheros.

Page 76: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 76 de 89

Memoria Dinámica

Aunque el lenguaje NO define ninguna facilidad para asignación de

almacenamiento que no sea definición estática o automática (usando la pila) no

emplea el head y no define mecanismo de recolección de basura, la biblioteca

estándar facilita un sistema de gestión dinámica de memoria (utilizando el

montón) cuyo núcleo está compuesto por las funciones malloc() y free(). Estas

funciones trabajan junta para establecer y gestionar la memoria disponible. La

función malloc asigna memoria y la función free la libera.

Cualquier programa que utiliza las funciones malloc y free debe incluir el archivo

de cabecera <stdlib.h>. Los prototipos de ambas funciones son:

void *malloc(size_t numero_de_bytes)

Donde el número de bytes es la cantidad de memoria que se requiere y

malloc retorna un void * que se asignar a cualquier tipo de apuntador. Si

hay un fallo durante la asignación malloc retorna nulo (NULL).

La función free en la complementaria a malloc ya que devuelve al sistema

la memoria previamente asignada-

void free(void *p)

Ahora p es apuntador previamente asignado. Es muy importante no llamar

nuca a free con un argumento no valido, se dañaría el sistema de

asignación. Ahora hay otras funciones para la gestión de memoria, para

mayor información revisar las referencias del lenguaje.

A continuación se muestra un ejemplo del uso de memoria dinámica en la

implementación de la función mystrdup que obtiene una asignación de espacio

de memoria antes de realizar la copia a diferencia de la función mystrcpy que

asume que el apuntador de destino contiene un espacio asignado para realizar

la copia

/*

* UCAB Guayana

* Introduccion al Lenguaje C

Page 77: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 77 de 89

*/

#include <stdio.h>

#include <malloc.h>

char *B, *A = "HOLA MUNDO";

int mystrlen(const char *s){

const char *p = s;

while(*p)

p++;

return p-s; }

void mystrcpy(char *d,const char *f){

while(*d++=*f++);

}

char *mystrdup(const char *f){

char *p;

p = (char *)malloc(mystrlen(f)+1);

if(p!=NULL)

mystrcpy(p,f);

return p;

}

int main(void){

printf("A:%s\n",A);

printf("Longitud A:%d\n",mystrlen(A));

B = mystrdup(A);

printf("B:%s\n",B);

return 0;

}

/* --- Fin ejemplo --- */

Como se puede observar los apuntadores proporcionan el soporte

necesario para la asignación de memoria dinámica. La asignación

dinámica es la forma como un programa puede obtener, de forma

explícita, memoria mientras se está ejecutando. Lo cual puede resultar útil

cuando el programa no conoce por anticipado las necesidades de

almacenamiento.

Page 78: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 78 de 89

Funciones con un número de parámetros variables

En C es posible crear funciones que reciban un número no especificado de

argumentos, un buen ejemplo puede ser la función printf. En el prototipo de la

función los puntos suspensivos (…) indica que la función recibe un número

variable de argumentos de cualquier tipo:

int printf(const char *, …);

Las macros y definiciones necesarias para construir funciones con un número de

parámetros variables, se encuentran en archivo de encabezados <stdarg.h>

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

#include <stdarg.h>

double avg(int n, ...){

double total = 0;

int register i;

va_list ap;

va_start(ap,n);

for(i=1;i<=n;i++)

total+=va_arg(ap,double);

va_end(ap);

return total/n;

}

int main(void){

double a=1.0,b=2.0,c=3.0,d=4.0;

printf("avg con 2 parametros:%f\n",avg(2,a,b));

printf("avg con 3 parametros:%f\n",avg(3,a,b,c));

printf("avg con 4 parametros:%f\n",avg(4,a,b,c,d));

printf("avg con 5

parametros:%f\n",avg(5,5.0,10.0,15.0,20.0,25.0));

return 0;

}

/* --- Fin ejemplo --- */

Page 79: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 79 de 89

Pase de parámetros a la función main

En los entornos que maneja C, hay una forma de transmitir al programa los

argumentos de la línea de comando. Cuando se invoca al main al comienzo de

la ejecución, se llama con dos argumentos. El primero (argc) es el número de

argumentos en la línea de comando con que se invoco al programa; el segundo

(argv) es un apuntador a un arreglo de cadenas de caracteres, que contiene los

argumentos uno en cada una de las cadena.

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

int main(int argc,char *argv[]){

if(argc>0)

printf("Argumento 1 %s\n",*argv++);

if(argc>1)

printf("Argumento 2 %s\n",*argv++);

if(argc>2)

printf("Argumento 3 %s\n",*argv++);

return 0;

}

/* --- Fin ejemplo --- */

Page 80: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 80 de 89

El preprocesador

El preprocesador se ejecuta al comenzar el proceso de compilación, es decir una

fase previa a éste, y se encarga de realizar ciertas tareas básicas; entre estas

tareas están la inclusión de archivos, expansión de macros y procesar de

directivas.

Las directivas del preprocesador empiezan por # y las principales son:

#include Incluir archivos.

#define Declara una macro o una constante

#undef Borra una macro de la tabla de definiciones.

#if, #ifdef, #ifndef, #else, #elif y #endif

Son utilizadas para Compilación Condicional. Se puede

preguntar por el valor de una constante o la existencia o no

de una macro. En caso de ser cierta la condición se compila

el código entre #if y #else, en caso de ser falsa se compila el

código entre #else y #endif.

#error, #line, #pragma

Consideraciones sobre macros

Debido a que el preprocesador de macros trabaja por simple reemplazo, se

pueden cometer algunos errores, para evitarlos se siguen unas simples

convenciones:

Colocar paréntesis alrededor de los argumentos siempre que sea posible:

Incorrecto: #define square(x) x*x

Mejor: #define square(x) (x)*(x)

Colocar paréntesis alrededor de la expresión entera, para que el orden de las

operaciones no afecte el resultado.

Incorrecto: #define square(x) (x)*(x)

Mejor: #define square(x) ((x)*(x))

Page 81: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 81 de 89

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

#define MAX(X,Y) ((X)>(Y)?(X):(Y))

int main(void){

int a,b;

printf("Un entero:");

scanf("%d",&a);

printf("Otro entero:");

scanf("%d",&b);

#ifdef DEPURAR

printf("valor a:%d\n",a);

printf("valor b:%d\n",b);

#endif

printf("Maximo entre %d y %d es %d\n",a,b,MAX(a,b));

return 0;

}

/* --- Fin ejemplo --- */

Page 82: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 82 de 89

Llamadas a otros lenguajes de programación

C soporta compilación separada, y posteriormente se enlazan los diferentes

módulos para crear el ejecutable, ahora no necesariamente todos los módulos

deben estar programado en C, como es el caso que se muestra a continuación,

donde un programa escrito en lenguaje C invoca a una función escrita en

fortran77.

Archivo en C

#include <stdio.h>

extern void fortfunc_(int *a, int *b);

int main(){

int a=1,b=2;

printf("Antes a:%d b:%d\n",a,b);

fortfunc_(&a, &b);

printf("Despues a:%d b:%d\n",a,b);

return 0;

}

Archivo en Fortran77

subroutine fortfunc(i,j)

integer i

integer j

i=5

j=6

return

Page 83: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 83 de 89

end

Salida

E:\Pruebas

Antes a:1 b:2

Despues a:5 b:6

Page 84: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 84 de 89

Caso de estudio: implementar un comando del sistema

El lenguaje C es utilizado en para programar partes del sistema de operación y/o

utilidades, a continuación se muestra la implementación de un comando del

sistema cat que escribirá a la salida estándar el contenido de cada uno de los

archivos dados como argumentos, en el mismo orden en el que fueron dados. Si

no se especifica ningún archivo, leerá sólo de la entrada estándar

/*

* UCAB

* Introduccion al Lenguaje C

* Comando cat como en UNIX

*/

#include <stdio.h>

#include <stdlib.h>

/*

* Copia el archivo fp en la salida estandar

*/

void filecopy(FILE *fp){

int c;

while((c=getc(fp))!=EOF)

putc(c,stdout);

}

int main(int argc, char* argv[]){

FILE *fp;

if(argc==1)

filecopy(stdin);

else

while(--argc>0)

if((fp=fopen(*++argv,"r"))==NULL){

fprintf(stderr,"cat: can't open %s\n",*argv);

exit(EXIT_FAILURE);

}

else{

filecopy(fp);

fclose(fp);

}

exit(EXIT_SUCCESS);

}

/* fin del ejemplo */

Page 85: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 85 de 89

Algoritmos y aplicaciones

A continuación se muestran algunos programas que pueden ser de interés

Implementar conjuntos con bits

/*

* UCAB Guayana

* Introduccion al Lenguaje C

*/

#include <stdio.h>

#define METER(B,S) (B|=1<<S)

#define SACAR(B,S)(B&=~(1<<S))

#define PERTENECE(B,S)(B>>S&1)

typedef unsigned long Conjunto;

Conjunto C_vaciar(void){

return 0;

}

Conjunto C_meter(Conjunto c, int e){

if(e>=0 && e<sizeof(Conjunto)*8)

return (c|1<<e);

return c;

}

Conjunto C_sacar(Conjunto c, int e){

if(e>=0 && e<sizeof(Conjunto)*8)

return (c&~(1<<e));

return c;

}

int C_pertenece(Conjunto c,int e){

if(e>=0 && e<sizeof(Conjunto)*8)

return (c>>e&1);

return 0;

}

void C_imprime(Conjunto c){

register int i;

printf("{ ");

for(i=0;i<sizeof(Conjunto)*8;i++,c>>=1)

if(c&1)

printf("%d ",i);

printf("}\n");

}

Conjunto C_union(Conjunto A, Conjunto B){

Page 86: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 86 de 89

return A|B;

}

Conjunto C_interseccion(Conjunto A, Conjunto B){

return A&B;

}

int main(void){

char *r[2]={"No","Si"};

Conjunto A,B,C;

A=C_vaciar();

B=C_vaciar();

A=C_meter(A,0);

A=C_meter(A,5);

A=C_meter(A,10);

B=C_meter(B,10);

B=C_meter(B,15);

C=C_union(A,B);

printf("A:");

C_imprime(A);

printf("B:");

C_imprime(B);

printf("A Union B:");

C_imprime(C);

printf("A Interseccion B:");

C_imprime(C_interseccion(A,B));

C=C_sacar(C,10);

printf("C:");

C_imprime(C);

printf("%d %s pertenece a C",5,r[C_pertenece(C,5)]);

return 0;

}

/* --- Fin ejemplo --- */

Page 87: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 87 de 89

Bibliografía recomendada

Kernigan Brian & Ritchie Dennis, El lenguaje de programación C, Segunda

edición, Prentice Hall, 1988.

Deitel P.J. & Deitel H.M., Como programar en C/C++, Prentice Hall, 1995.

American National Standards Institute, Programming Language C, ANSY

X3.159-1989.

Schildt Herbert, C Manual de referencia, Cuarta edición, McGraw-Hill, 2001.

Joyanes A. Luis, Castillo S. Andrés, Sánchez G. Lucas & Zahonero M. Ignacio,

Programación en C – Libro de Problemas, McGraw-Hill, 2002.

Page 88: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 88 de 89

ANEXOS

Page 89: Introducción al Lenguaje C

Introducción al

Lenguaje de Programación C

Octubre 2010 Página 89 de 89

Anexo A

Ejemplo de algunas declaraciones que pueden ser de ayuda y utilidad para

entender o hacer declaraciones, sobre todo cuando se utilizan apuntadores.

int i; // integer variable

int *p; // pointer to integer variable

int a[]; // array of integer

int f(); // function with return value integer

int **pp; // pointer to pointer to integer

int (*pa)[]; // pointer to an array of integer

int (*pf)(); // pointer to a function with return value integer

int *ap[]; // array of pointers to integer

int *fp(); // function, which returns a pointer to an integer

int ***ppp; // pointer to a pointer to a pointer to integer

int (**ppa)[]; // pointer to a pointer to an array of integer

int (**ppf)(); // pointer to a pointer to a function with return value integer

int *(*pap)[]; // pointer to an array of pointers to integer

int *(*pfp)(); // pointer to function with return value pointer to integer

int **app[]; // array of pointer to pointer to integer

int (*apa[])[];// array of pointers to array of integer

int (*apf[])();// array of pointers to functions with return value integer

int ***fpp(); // function with return value pointer to pointer to pointer to int

int (*fpa())[];// function with return value pointer to array of integers

int (*fpf())();// function with return value pointer to function, which returns an

integer