Escolar Documentos
Profissional Documentos
Cultura Documentos
Introducción
El presente curso de introducción al C está pensado para ser impartido en unas 10 horas
de clase. Se supone como prerequisito que el alumno ya conoce Pascal, y por ello
muchas de las construcciones de C se estudian muy por encima, pues son absolutamente
análogas a su contrapartida Pascal.
1.1. Historia
El lenguaje C fue diseñado en los años sesenta por Dennis Ritchie, de los Laboratorios
Bell. El propósito era ser el lenguaje del sistema operativo UNIX.
Se diseñó junto con el sistema operativo UNIX y está muy orientado a trabajar en su
entorno.
El compilador debe ser lo más pequeño y eficiente posible. Pocas palabras reservadas,
esto es, un conjunto reducido de sentencias. No existe anidamiento de procedimientos.
La entrada/salida no se considera parte del lenguaje en sí, sino que se suministra a través
de funciones de librería. La misma política se sigue con cualquier otro tipo complejo de
instrucciones.
Para escribir un programa se debe poder escribir poco texto. Para lograr esto se reduce
el número de palabras claves.
Con ello se llegó a un compilador con un poderoso juego de instrucciones, que permite
aumentar la productividad/día de los programadores.
A pesar de ello el C es un lenguaje rápido de aprender, que deriva en compiladores
sencillos de diseñar, robustos, y que generan objetos pequeños y eficientes.
• programación de sistemas
• estructuras de datos y sistemas de bases de datos
• aplicaciones científicas
• software gráfico
• análisis numérico
1.3. Críticas
Dentro de las principales críticas que se le achacan podemos destacar:
for(i=0;i<10;i++)
for (j=0;j<10;)
*(*(x+i)+j++)=(y[i][j]>*(*(z+i)+j))?1:2;
for (;*a|*b;*p++=(*a>*b)?*a++;*b++);
Figura 1 Programas crípticos
Las palabras reservadas de C, que no pueden ser definidas por el usuario son las que se
listan en la Figura 4. También existen algunas otras que se han añadido en
implementaciones posteriores.
3 Tipos de Datos
C utiliza 5 palabras reservadas para definir los tipos de datos fundamentales. A
diferencia de Pascal, un determinado tipo de datos puede ir cualificado por un conjunto
de modificadores que estudiaremos más adelante.
Los tipos de datos fundamentales son:
Los tipos short int, long int, unsigned int y long float se pueden escribir como: short,
long, unsigned y double.
Con respecto al tamaño que ocupan en memoria variables de estos tipos, todo lo que
garantiza C es:
sizeof(char) = 1
sizeof(short) <= sizeof(int) <= sizeof(long)
sizeof(unsigned) = sizeof(int)
sizeof(float) =< sizeof(double)
Hay un grupo de modificadores que indican la forma que se almacena una determinada
variable de un determinado tipo. Se indica antes del tipo de la variable.
static
Cuando se invoca a una función por segunda vez se pierden los valores que las variables
locales de la función tenían al acabar la anterior llamada. Declarando una variable de
este tipo cuando se llama por segunda vez a la subrutina la variable static (estática)
contiene el mismo valor que al acabar la llamada anterior.
auto
Es lo mismo que si no se usara ningún modificador
volatile
El compilador debe asumir que la variable está relacionada con un dispositivo y que
puede cambiar de valor en cualquier momento.
register
El compilador procurará almacenar la variable cualificada de este modo en un registro
de la CPU.
extern
La variable se considera declarada en otro fichero. No se le asignará dirección ni
espacio de memoria.
4. Estructuras de datos
struct Es análoga al constructor record de Pascal. Su sintaxis es:
struct nombre {
tipo miembro1;
tipo miembro2;
...
} identificador1, identificador2, ...;
Para acceder a los campos de la estructura se usa la misma técnica que en Pascal:
variable.miembro
Se admite el uso de estructuras dentro de la declaración de otra estructura ya que los
miembros, en general, pueden tener cualquier tipo.
struct fecha {
int mes;
int día;
int año;
}; /* Estructura fecha */
struct cuenta {
int cuen_no;
char cuen_tipo;
float saldo;
struct fecha ultimo_pago;
} cliente[100]; /* Estructura cuenta y declaración */
struct cuenta clientes[20];
clientes[0].cuen_no = cliente[99].ultimo_pago.anio;
Figura 6 Ejemplo de struct
union Es una construcción análoga al registro con variante de Pascal. Al igual que las
estructuras constan de varios miembros aunque éstos comparten la misma ubicación de
memoria. Se usa para hacer referencia a una misma área de memoria de varias formas.
El tamaño de la unión es el tamaño del miembro mayor.
La forma de declarar una unión es:
nuevo-tipo es el nombre del tipo que se va a definir y tipo puede ser todo lo complicado
que se quiera siempre que esté definido con los tipos ya existentes.
typedef struct {
int mes;
int día;
int anio;
} fecha; /* Declaración de un nuevo tipo llamado fecha
*/
fecha hoy; /* Declaración de una variable de tipo fecha */
enum Es análogo a un tipo enumerado de Pascal. Sirve para especificar los miembros
de un determinado tipo.
5. Declaración de variables
La forma general de declarar variables en C es la siguiente:
Las expresiones = valor sirven para inicializar la variable y pueden ser opcionales.
Las variables pueden ser declaradas en dos puntos: dentro de un bloque antes de la
primera línea ejecutable; en este caso el ámbito de la variable es el cuerpo del bloque y
fuera de todos los procedimientos, en este caso, el ámbito abarca a todas las funciones,
es decir son declaraciones globales. El cuerpo de una función es considerado como un
bloque.
6. Arrays
En C los arrays son de tamaño fijo, es decir, su tamaño se especifica en tiempo de
compilación.
nombre[expresión][expresión]...
Las cadenas son consideradas como vectores de caracteres. Acaban con el carácter nulo
'\0'. Pueden tener una longitud arbitraria y el primer byte corresponde al primer caracter.
No se almacena la longitud de la cadena como parte de la misma (como ocurre en Turbo
Pascal).
0 Entero
9999 Entero
0x Entero (hexa)
0x1 Entero (hexa)
0X7FFF Entero (hexa)
0xabcd Entero (hexa)
05270 Entero (octal)
50000U Entero (sin signo)
123456789L Entero (largo)
123456789UL Entero (largo y sin signo)
01234L Entero (octal y largo)
077777UL Entero (octal, largo y sin signo)
0x456L Entero (hexa y largo)
0XFFFFUL Entero (hexa, sin signo y largo)
0. Flotante (double)
0.2 Flotante (double)
.8 Flotante (double)
2E-2 Flotante (double)
2e3 Flotante (double)
2.2e+5 Flotante (double)
0.12L Flotante representado con larga precisión
.12e6F Flotante representado con simple precisión
'A' Caracter A
'$' Caracter dolar
'\n' Caracter retorno de carro
'\x20' Caracter espacio
"verde" Cadena
"verde\n" Cadena que termina con un carry return
"\"RETURN\"\n" Cadena que contiene RETURN entre comillas
terminado en retorno de carro.
Figura 12 Ejemplos de constantes
8. Punteros
Los punteros 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 puntero. Cuando se declara un puntero é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.
El tipo indica al tipo de datos a los que apuntará el puntero, pero como efecto de la
declaración se reservará espacio en memoria para guardar un puntero, no para el tipo de
datos al que apunta.
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 puntero. A estos dos símbolos se les
llama dirección e indirección respectivamente.
Hay 3 formas de inicializar un puntero:
p = (T*)malloc(sizeof(T));
main(void) {
int a, b;
a = b = 0;
func(&a, b);
/* En este punto ¿cuánto valen a y b? */
return;
}
Figura 13 Ejemplo de paso de punteros a una función
tipo nombre[expresion1][expresion2]...;
nombre[expresion1][expresion2]...
También se puede hacer referencia a los elementos de una matriz usando la técnica de
punteros pero el texto se hace demasiado críptico.
tipo *nombre[expresion1][expresion2];
9. Expresiones
El C permite operar dos expresiones de cualquier tipo con cualquier operador. Es
responsabilidad del programador conocer la interpretación que hará el compilador.
En operaciones lógicas y comparaciones el valor falso se representa con un cero y el
verdadero es cualquier otro número, siendo 1 el que devuelven dichas operaciones.
9.5. Asignaciones
= Asignación
+= ejemplo: a = a + 3 es equivalente a: a += 3
-= ejemplo: a = a - 3 es equivalente a: a -= 3
*= ejemplo: a = a * 3 es equivalente a: a *= 3
/= ejemplo: a = a / 3 es equivalente a: a /= 3
%= ejemplo: a = a % 3 es equivalente a: a %= 3
^= ejemplo: a = a ^ 3 es equivalente a: a ^= 3
&= ejemplo: a = a & 3 es equivalente a: a &= 3
|= ejemplo: a = a | 3 es equivalente a: a |= 3
>>= ejemplo: a = a >> 3 es equivalente a: a >>= 3
<<= ejemplo: a = a << 3 es equivalente a: a <<= 3
int a, b, c;
a = b = c = 0;
a += b = c;
Figura 16 Ejemplos de asignaciones
x = f(y);
if (x == N) ...
Expresión Tipo
c - s / i int
u * 3 - i unsigned
u * 3.0 - i double
f * 3 - i float
c + 1 int
c + 1.0 double
Figura 17 Conversiones implícitas
10. Sentencias
En C hay tres tipos de sentencias: las de expresión, las compuestas y las de control de
flujo.
Las sentencias de expresión son aquellas en las que se especifica una expresión para
evaluar y que devuelven un valor. Acaban siempre con el símbolo ";".
Las sentencias compuestas son las que comienzan por llaves abiertas y acaban con
llaves cerradas, conteniendo en su interior en primer lugar las posibles declaraciones
(locales al ámbito de la sentencia) y a continuación una lista de sentencias.
Las sentencias de control de flujo son las de bucle (for, while, switch y do), la
condicional (if) y las de salto (goto, continue y break).
Se repite la sentencia mientras el valor de expresión sea cierto (no 0). La condición se
evalúa antes de ejecutar la sentencia.
expresion1;
while (expresion2) {
sentencia;
expresion3;
}
10.3 Sentencia if
if (expresión) sentencia1 else sentencia2
Igual que en Pascal la parte else es opcional. La sentencia1 se ejecuta si expresión tiene
un valor verdadero (distinto de 0) y si tiene un valor falso (0) se ejecuta la sentencia2.
if (estado == 'S')
tasa = 0.20 * pago;
else
tasa = 0.14 * pago;
Se repite la sentencia mientras expresión sea cierta (no 0). Es análoga al repeat de
Pascal. La expresión se evalúa después de ejecutar la sentencia, por lo que esta se
ejecuta al menos una vez.
Se usa para romper una sentencia while, do-while, for o switch. Si se ejecuta se sale del
bucle más interno o de la sentencia switch que se esté ejecutando.
char color;
switch (color) {
case 'a':
case 'A': printf("AMARILLO\n");
break;
case 'r':
case 'R': printf("ROJO\n");
case 'b':
case 'B': printf("BLANCO\n");
default: printf("OTRO\n");
}
Figura 22 break
Esta sentencia anula la pasada actual de un bucle. Se ejecuta la siguiente pasada del
bucle más interno en el que se encuentre ignorándose el código que se tendría que
ejecutar para acabar la pasada actual. Se puede usar en los bucles for, while y do-while
10.8 Sentencia goto
goto etiqueta
11. Funciones
El lenguaje C sólo permite funciones, no hay procedimientos. La forma de declarar las
funciones es la siguiente:
Donde tipo es el tipo del dato que devuelve la función, que si no aparece se supone
siempre int, y nombre es el identificador de la función.
La forma de invocar a una función es la misma que en Pascal, 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) delante de la invocación de la función:
(void)printf("\n");
Las listas de parámetros formales y de parámetros actuales no tienen por qué coincidir
en número, e incluso en tipo. Si hay más parámetros formales que actuales se les asigna
un valor indefinido a los formales; si ocurre al revés se descartan los parámetros
actuales que sobren. 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:
return [expresión];
Donde la expresión es el valor que retorna la función. Debe ser del mismo tipo que el de
la función.
/* trozo de programa */
void funcion1(int a) { /* Función 1 */
/* Cuerpo de la función */
funcion2();
}
12. Librerías
En el lenguaje C toda la entrada y salida de un programa se realiza a través de funciones
definidas en librerías. También se encuentran definidas en librerías otros tipos de
funciones. Dichas librerías, 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 fichero se debe indicar las declaraciones de las librerías que se utilizarán. Esto se
realiza utilizando la directiva #include, cuya sintaxis es:
#include nombre_fichero
donde el nombre del fichero donde se realizan las definiciones se coloca entre ángulos
(<nombre_fichero>) o entre comillas dobles ("nombre_fichero") según el lugar en que
haya que buscar el fichero sea en los directorios asignados por defecto a los ficheros
'include' o en el actual.
Estos ficheros de definiciones suelen tener la extensión .h (de header, cabeceras) y
contienen definiciones necesarias para la utilización de las funciones contenidas en las
librerías.
Por otra parte, utilizando la directiva #include se puede hacer inclusión de ficheros de
código del mismo modo que en cualquier otro lenguaje.
Convierte s a minúsculas.
• 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
%c Caracter
%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)
Figura 25 Caracteres de conversión
#include <stdio.h>
int main(void) {
FILE *fp;
char a;
int b, c;
fp = fopen("fichero.txt", "r+");
if (fp == NULL) {
printf("ERROR");
exit(-1);
}
fscanf(fp, "%c %d, %d", &a, &b, &c);
fclose(fp);
return 0;
}
Figura 27 Lectura de datos de un fichero
tipo (*nombre)();
Donde tipo es el tipo que devuelve la función y nombre es el identificador del puntero a
la función. Para darle una dirección a este puntero se realiza una asignación donde en la
parte derecha debe haber un nombre de función. Cuando se haga uso del puntero se
estará haciendo una llamada a la función.
int funcion1(int a) {
/* Cuerpo de la función */
}
void funcion2(void) {
int a, (*pun_fun)();
pun_fun = funcion1;
a = (*pun_fun)(2);
return ;
}
Figura 29 Punteros a funciones
El compilador C lee el fichero fuente una sola vez. Esto quiere decir que si queremos
utilizar un identificador tenemos que declararlo antes. Esto no ocurre con las funciones
que pueden ser declaradas en el orden que se desee, pero en este caso el compilador no
comprueba que los tipos ni que la cantidad de los parámetros formales y actuales
coincidan.
15. Preprocesador de C
El preprocesador actúa antes que el compilador. El nombre del preprocesador es CPP
(CPP.EXE en el caso de DOS). Es una fase previa a éste, y se encarga de realizar ciertas
tareas básicas; entre estas tareas están la inclusión de ficheros, expansión de macros y
proceso de directivas.
15.1. #include
Se usa para incluir un fichero.
#ifdef DEBUG
/* Código para depuración */
#else
/* Código definitivo (sin depuración) */
#endif
1º:
while ('\n' != *p++=*q++);
2º:
while (1) {
*destination_ptr = *source_ptr;
destination_ptr++;
source_ptr++;
if (*destination_ptr == '\n')
break; /* abandonar el bucle si se ha acabado */
}
Aunque la segunda versión es más larga, es más clara y fácil de comprender. Incluso un
programador sin demasiada experiencia en C puede entender que este código tiene algo
que ver con mover datos desde una fuente hacia un destino. Al compilador no le
importa cuál de las dos versiones se utilice: un buen compilador generará el mismo
código máquina para ambas. Es el programador quien se beneficia de la claridad del
código.
16.2. Legibilidad
• Haga todo lo posible para incrementar la legibilidad de sus
programas. En concreto:
o Coloque siempre un espacio después de las comas
y puntos y comas: Es preferible
for (i = 1; i <= MAX; i++)
que
for(i=1;i<MAX;i++)
16.4. Declaraciones
• Coloque una declaración de variable por cada línea, y comente el significado de
cada variable significativa para comprender el código.
• Utilice identificadores lo suficientemente significativos como para comprender su
significado y lo suficientemente cortos como para que sean fáciles de escribir.
• Nunca utilice declaraciones por defecto: si una función retorna un entero, declárela
de tipo int. Todos los parámetros de una función deben ser declarados y
comentados.
• Los identificadores de las constantes y macros se suelen escribir en mayúscula y el
resto de identificadores en minúscula.
X:\PROG\COMP\BC20\BIN
17.1. Lint
El programa lint (disponible en entornos UNIX, PC-lint es la versión para PC's) toma
como entrada un fichero que contiene código C y emite diversos mensajes cuyo objetivo
es mejorar la corrección, eficacia y portabilidad de los programas C. Por ejemplo, lint
indica datos o funciones declarados pero no utilizados; también detecta partes del
código que inadvertidamente nunca serán ejecutadas, detecta variables declaradas y no
utilizadas etc.. En términos generales, siempre debe emplearse lint antes de proceder a
la compilación final.
Con frecuencia, el gran número de mensajes de aviso e información que Lint genera es
demasiado grande; por ello se puede proceder a inhibir la generación de ciertos
mensajes, pero hemos de advertir que ello ha de hacerse con conocimiento exacto del
significado del mensaje que se ha generado.
Para depurar ciertos ficheros (f1.c, f2.c ...) usando PC-Lint en la red Novell del C.S.I.
basta escribir:
co-tc.lnt: Contiene ciertas opciones para ser utilizadas con los compiladores de
Turbo C, Turbo C++ y Borland C++
-eN
Si se ejecuta X:\CAMINO\LINT sin más opciones, PC-Lint mostrará todas las opciones
disponibles. El usuario puede crear su propio fichero de comandos para invocar PC-Lint
utilizando las opciones que más le interesen en cada momento.
Desde el entorno integrado del Borland C++ 2.0 se puede invocar PC-Lint utilizando la
opción "Lint" del menú ? (el que se encuentra a la izquierda del de Archivo en la barra
de menús). Las opciones que utiliza PC-Lint en este caso pueden verse en el menú de
opciones, bajo el epígrafe "Transfer".
17.2. Grep
La utilidad grep se utiliza para buscar la aparición de una determinada cadena de
caracteres en un fichero de texto. Con frecuencia un programador no recuerda el nombre
del fichero en el que realizó cierto trabajo, pero sí recuerda un identificador de variable
o función que se utilizaba en aquél fichero. Grep permite buscar todas las apariciones de
una cadena de caracteres en un conjunto de ficheros. La Figura 32 muestra todas las
opciones que adminte la versión 3.0 del Grep de Borland:
17.3. Make
La utilidad make también es un estandar en entornos de programación UNIX. make se
utiliza para mantener los programas acutalizados según su última versión a través de las
siguiente serie de acciones:
La utilidad make es tanto más conveniente cuanto más complejo sea el programa
ejecutable que se está construyendo. La situación ideal es cuando el fichero ejecutable
consta de muchos módulos que pueden ser compilados separadamente.
La documentación correspondiente a la utilidad make de Borland así como la del
TLINK (Linker de Borland) está disponible para los alumnos.
18. Ejemplos
/
**********************************************************************
******
PROGRAMA: Adios
AUTOR: Kiko
FECHA: 12.07.94
FINALIDAD: Cl sico primer programa en C
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: No requiere entrada alguna
**********************************************************************
******/
#include <stdio.h>
void main(){
printf("Adi¢s, mundo cruel...");
}
/
**********************************************************************
******
PROGRAMA: sizeof
AUTOR: Kiko
FECHA: 03.10.94
FINALIDAD: Ilustrar los tama¤os en memoria de los tipos
fundamentales.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: -
**********************************************************************
******/
#include <stdio.h>
#define C1 0.1
#define C2 0.1L
int vector[10];
char cadena1[] = "abc";
char cadena2[] = {'a', 'b', 'c'};
int *ip;
char *cp;
void main(void){
printf("tama¤o de char: %d\n", sizeof(char));
printf("tama¤o de short int: %d\n", sizeof(short int));
printf("tama¤o de int: %d\n", sizeof(int));
printf("tama¤o de long int: %d\n", sizeof(long int));
printf("tama¤o de unsigned short int: %d\n", sizeof(unsigned
short int));
printf("tama¤o de unsigned int: %d\n", sizeof(unsigned int));
printf("tama¤o de unsigned: %d\n", sizeof(unsigned));
printf("tama¤o de unsigned long int: %d\n", sizeof(unsigned
long int));
printf("tama¤o de float: %d\n", sizeof(float));
printf("tama¤o de double d: %d\n", sizeof(double));
/* Definici¢n de constantes */
#define c1 5000U
#define c2 123456789L
#define c3 123456789UL
#define c4 0123456L
#define c5 0X500U
#define c6 'A'
#define c7 65
#define c8 "Esto es una cadena de caracteres constante"
void main()
{
int i = 1;
unsigned u = 2;
char c = 65;
float f = 3.0;
double d = 4.0;
clrscr();
printf("Un entero: %d\n", i);
printf("Un entero sin signo: %d\n", u);
printf("Un caracter: %c\n", c);
printf("Un real en punto flotante: %f\n", f);
printf("Un real en doble precisi¢n: %lf\n", d);
#define N 2
#define M 3
/* Definiciones de estructuras */
struct fecha {
int mes;
int dia;
int anio;
};
struct alumnos {
char nombre[20];
char apellido1[20];
char apellido2[20];
unsigned long int dni;
int curso;
} alu1, alu2, alu3;
struct lista {
char elemento[10]; /* Elemento de la lista */
struct lista *sig; /* Puntero al siguiente nodo */
};
/* Variables estructuradas */
struct fecha f;
struct alumnos alu4, alu5, alu6;
struct lista L;
/*
alu1, alu1, alu3, alu4, alu5 y alu6 son todas variables estructuradas
del
tipo alumnos. N¢tese las distintas formas de declarar estas variables.
*/
void main()
{
int i;
clrscr();
for (i = 0; i < N; i++)
vector[i] = i;
strcpy(alu1.nombre, "Miguel");
strcpy(alu1.apellido1, "Cervantes");
strcpy(alu1.apellido2, "Saavedra");
alu1.dni = 123456;
#include <stdio.h>
#include <stdio.h>
#define N 100
/*
struct alfa {
int c1;
char c2;
};
main()
{
byte b;
int i;
vectores v;
prueba s;
}
/
**********************************************************************
******
PROGRAMA: const_ch.c
AUTOR: Kiko
FECHA: 05.10.94
FINALIDAD: Algunas pruebas con constantes de caracteres.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: Sin requerimientos especiales.
**********************************************************************
******/
#include <stdio.h>
void main(){
char vector1[] = "abc";
char vector2[] = {'x', 'y', 'z'};
char c;
int i;
c = 'a';
printf("Caracter: %c\n", c);
i = (int)c;
printf("N£mero (formateando como entero): %d\n", i);
/
**********************************************************************
******
PROGRAMA: pre_post
AUTOR: Kiko
FECHA: 07.10.94
FINALIDAD: Ilustrar el uso de los operadores ++ y --.
COMENTARIOS: Intentar predecir la salida del programa. Tener en
cuenta el
comportamiento de
los operadores:
-
preincremento y predecremento primero modifican la
variable
y luego eval£an la expresi¢n en la que ‚sta
interviene.
-
postincremento y postdecremento primero eval£an la expresi¢n
con el
valor actual de la variable y luego modifican la
variable.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: -
**********************************************************************
******/
#include <stdio.h>
#include <stdlib.h>
void main(void){
int x, a;
a = 1;
printf("a = %d\n", a);
printf("a = %d\n", ++a);
printf("a = %d\n\n", a);
a = 1;
printf("a = %d\n", a);
printf("a = %d\n", a++);
printf("a = %d\n\n", a);
a = 1;
x = 7 + (++a);
printf("Valor de la expresi¢n con preincremento: %d\n", x);
a = 1;
x = 7 + (a++);
printf("Valor de la expresi¢n con postincremento: %d\n", x);
}
/
**********************************************************************
******
PROGRAMA: args
AUTOR: Kiko
FECHA: 12.07.94
FINALIDAD: Ilustrar la captura de los par metros de l¡nea de
comandos
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: El fichero ejecutable es autoexplicativo
**********************************************************************
******/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
clrscr();
if (argc < 2) {
printf("Modo de uso: args par_1 par_2 par_3 ... par_N\n");
exit(0);
}
/
**********************************************************************
******
PROGRAMA: assign.c
AUTOR: Kiko
FECHA: 05.10.94
FINALIDAD: Estudiar el valor devuelto por las asignaciones.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: Sin requerimientos especiales.
**********************************************************************
******/
#include <stdio.h>
void main(){
int a, b, c;
a = 7;
a += b = 7;
printf("Valor de b: %d\n", b);
printf("Valor de a: %d\n", a);
a = b = c = 99;
printf("Valor de b: %d\n", b);
printf("Valor de a: %d\n", a);
printf("Valor de c: %d\n", c);
}
/
**********************************************************************
******
PROGRAMA: ambito.c
AUTOR: Kiko
FECHA: 05.10.94
FINALIDAD: Estudiar el mbito de las variables declaradas.
COMENTARIOS: Tratar de compilar el programa y observar los errores que
se
producen cuando se accede a variables
fuera de ambito.
Eliminar el error comentando la
sentencia en que se produce y
volver a compilar.
Hacer prueba poniendo los accesos a las
diferentes variables en
diferentes puntos.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: Sin requerimientos especiales.
**********************************************************************
******/
#include <stdio.h>
/
**********************************************************************
******/
void f(void){
int a3 = 3; /* Ambito en el cuerpo de la funci¢n */
}
/
**********************************************************************
******/
void main(void){
int a2 = 2; /* Ambito en el cuerpo de la funci¢n
main */
while (1) {
int a4 = 4; /* Ambito: bloque del bucle while */
/
**********************************************************************
******
PROGRAMA: scan1.c
AUTOR: Kiko
FECHA: 27.10.94
FINALIDAD: Ilustrar los formateadores de funciones tipo scanf,
fscanf, etc.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: No requiere entrada alguna
**********************************************************************
******/
#include <stdio.h>
void main(void){
char letras[50]; /* Para leer cadenas de
caracteres */
int entero;
float real;
int valor;
/
**********************************************************************
******
PROGRAMA: scan2.c
AUTOR: Kiko
FECHA: 27.10.94
FINALIDAD: Ilustrar los formateadores de funciones tipo scanf,
fscanf, etc.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: No requiere entrada alguna
**********************************************************************
******/
#include <stdio.h>
void main(void){
char letras[50]; /* Para leer cadenas de
caracteres */
int entero;
float real;
int valor;
/
**********************************************************************
******
PROGRAMA: scan3.c
AUTOR: Kiko
FECHA: 27.10.94
FINALIDAD: Ilustrar los formateadores de funciones tipo scanf,
fscanf, etc.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: No requiere entrada alguna
**********************************************************************
******/
#include <stdio.h>
void main(void){
char letras[50]; /* Para leer cadenas de
caracteres */
int entero;
float real;
int valor;
printf("Introduzca una cadena que contenga espacios en
blanco.\n");
valor = scanf("%[ abcdefghijklmn¤opqrstuvwxyz]", letras);
printf("\nCadena le¡da: %s\n", letras);
printf("Valor devuelto por scanf: %d\n", valor);
printf("Pruebe lo que ocurre si se introducen caracteres
diferentes de los permitidos.\n");
}
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char string[] = "123";
int value;
value = convert(string);
printf("value: %d\n", value);
return 0;
}
/
**********************************************************************
******
PROGRAMA: control.c
AUTOR: Kiko
FECHA: 05.10.94
FINALIDAD: Estudiar sentencias de control de C.
COMENTARIOS: Probar a realizar el mismo proceso con diferentes
sentencias
de repetici¢n. Experimentar con
este tipo de sentencias.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: Sin requerimientos especiales.
**********************************************************************
******/
#include <stdio.h>
void main(void){
int v[100], i = 0, media, suma = 0;
/
**********************************************************************
******
PROGRAMA: wc
AUTOR: Kiko
FECHA: 12.07.94
FINALIDAD: Utilidad wc de UNIX: Cuenta l¡neas, palabras y
caracteres de
un fichero de texto.
COMENTARIOS: Considera palabras cualquier secuencia de caracteres
que no
contenga espacios en blanco, tabuladores o fines de
linea (\n).
HISTORIA:
BIBLIOGRAFIA: K&R
"El lenguaje de programaci¢n C"
Kernighan & Ritchie
Ed. Prentice-Hall Hispanoamericana, S. A.
pg 20
MODO DE UTILIZACION: El programa ejecutable es autoexplicativo
**********************************************************************
******/
#include <stdio.h>
#include <stdlib.h>
#define CR '\r'
#define SPACE ' '
#define TAB '\t'
#define LF '\n'
if (argc < 2) {
printf("WC Word Counter.\nCounts Lines, Words and Chars in a
Text File\n\n");
printf("Usage: wc filename\n");
exit(0);
}
inword = FALSE;
nl = nw = nc = 0;
while ((c = fgetc(f)) != EOF) {
nc++;
if (c == CR)
nl++;
if (c == SPACE || c == CR || c == TAB || c == LF)
inword = FALSE;
else
if (inword == FALSE) {
inword = TRUE;
nw++;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
/
**********************************************************************
******
PROGRAMA: punt1
AUTOR: Kiko
FECHA: 07.10.94
FINALIDAD: Ilustrar el uso de identificadores de vector como
punteros.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: -
**********************************************************************
******/
#include <stdio.h>
#define size 5
void main(void){
int *p;
int v[size];
int i;
p = v;
for (i = 0; i < size; i++)
*(v + i) = i;
/* v = v + 2; */
}
/
**********************************************************************
******
PROGRAMA: punt2.c
AUTOR: Kiko
FECHA: 12.07.94
FINALIDAD: Mostrar el paso de par metros de punteros a funciones.
COMENTARIOS: El alumno debe comprender el comportamiento del
programa.
En caso de tener problemas,
estudie lo que ocurre cuando a una
funci¢n se pasa un par metro por
valor. A continuaci¢n
consid‚rese lo que ocurre cuando
ese par metro es un
puntero.
MODO DE UTILIZACION: El fichero ejecutable es autoexplicativo
**********************************************************************
******/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
/
*=====================================================================
=====*/
void f1(int *p) {
p = (int *)malloc(sizeof(int));
*p = 1;
printf("Dentro de f1: &p: %p *p: %6d\n", p, *p);
}
/
*=====================================================================
=====*/
void f2(int **p) {
/* Aqu¡ p es un puntero a puntero, y *p es un puntero */
*p = (int *)malloc(sizeof(int));
**p = 2;
printf("Dentro de f2: &p: %p *p: %6d\n", *p,
*(*p));
}
/
*=====================================================================
=====*/
int main(void) {
int *ip;
clrscr();
printf("Principio: &ip: %p *ip: %6d\n", ip, *ip);
f1(ip);
printf("Despu‚s de llamar a f1: &ip: %p *ip: %6d\n", ip, *ip);
f2(&ip);
printf("Despu‚s de llamar a f2: &ip: %p *ip: %6d\n", ip, *ip);
return 0;
}
/
**********************************************************************
******
PROGRAMA: pun_fun
AUTOR: Kiko
FECHA: 11.10.94
FINALIDAD: Ilustrar el uso de punteros a funci¢n
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: -
**********************************************************************
******/
#include <stdio.h>
int sumar_uno(int x) {
return(x + 1);
}
int restar_uno(int x) {
return(x - 1);
}
void main(void){
int i;
int (*puntero_a_funcion)();
i = (*puntero_a_funcion)(2); /*
LLamada a la funci¢n a trav‚s del puntero */
printf("Valor devuelto por la primera llamada: %d\n", i);
puntero_a_funcion = restar_uno;
i = (*puntero_a_funcion)(2); /*
LLamada a la funci¢n a trav‚s del puntero */
printf("Valor devuelto por la segunda llamada: %d\n", i);
}
/
**********************************************************************
******
PROGRAMA: quick.c
AUTOR: Kiko
FECHA: 14.10.96
FINALIDAD: quicksort
HISTORIA:
BIBLIOGRAFIA: Algoritmos + Estructuras de Datos = Programas. N.
Wirth.
MODO DE UTILIZACION:
**********************************************************************
******/
#include <stdlib.h>
#include <stdio.h>
items v[N];
void inicializa(void);
void escribe(void);
/
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::*/
void inicializa(void) {
unsigned i;
i = iz;
j = de;
pivot = v[(iz + de) / 2].clave;
do {
while (v[i].clave < pivot)
i++;
while (pivot < v[j].clave)
j--;
if (i <= j) {
temp = v[i]; /* intercambiar v[i] y v[j] */
v[i] = v[j];
v[j] = temp;
i++;
j--;
}
} while (i <= j);
if (iz < j)
quicksort(iz, j);
if (i < de)
quicksort(i, de);
}
/
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::*/
main() {
inicializa();
quicksort(0, N - 1);
escribe();
printf("Tama¤o de los items: %u bytes\n", sizeof(items));
return;
}
#include
Modo Accion
"r" Abre para lectura
Abre un archivo
"w" vacio para
escritura if
fopen(s1, FILE *fopen(const char
23 file(puntero) stdio.h Abre para ((corriente2=fopen("datos","W+"))==NULL
s2) *s1, const char *s2)
"a" escritura al final printf("El archivo...no se ha abierto \n");
del archivo
Abre para
"r+"
lectura/escritura
Abre un archivo
"w+" vacio para
lectura/escritura
Abre para lectura
"a+"
y anadir
Abre un archivo
"rb" binario para
lectura.
Abre un archivo
"wb" binario para
escritura
Abre un archivo
"ab" binario para
anadir
Abre un archivo
"rb+" binario para
lectura/escritura.
Abre un archivo
"wb+" binario para
lectura/escritura
Abre o crea un
archivo binario
"ab+"
para
lectura/escritura
int fprintf(FILE *f, const Escribe datos en el archivo f
24 fprintf(f, ...) int stdio.h fprintf(f1, "El resultado es %f\n",result);
char *formato [,arg,...]); (el resto de los argumentos
Escribe un caracter en el
25 fputc(c, f) int stdio.h int fputc(int c, FILE *f); fputc(*(p++), stdout);
archivo f
int fputs(const char *cad, Escribe una cadena de
26 fputs(s, f) int stdio.h fputs("esto es una prueba", f1);
FILE *f) caracteres en el archivo f
27 fread(s, i1, int stdio.h size_t fread(void *b, Lee i2 elementos, cada uno fread(buf, strlen(msg)+1, 1, flujo);
i2, f) size_t t, size_t n, FILE *f); de tamano i1 bytes, desde el
archivo f hasta la cadena s
char *cad;
Libera un bloque de
// asignar memoria a la cadena
malloc.h o void free(void memoria reservada cuyo
28 free(p) void cad=(char *)malloc(50);
stdlib.h *dir_memoria); principio esta indicado por
...
p.
free(cad); // liberar memoria
int fscanf(FILE *f, const
Lee datos del archivo f ( el
29 fscanf(f, ...) int math.h char *formato, [, fscanf(flujo, %s%f, cad, &f);
resto de los argumentos
direccion,... ]);
Mueve el puntero al archivo
f una distancia de 1 bytes
desde la posicion i (i puede
representar el principio del
archivo, la posicion actual
del puntero o el fin del
archivo.
Notas
int fseek(FILE *f, long
30 fseek(f, l, i) int stdio.h fseek(f1,OL,SEEK_SET); // ir al principio
desplaza, int origen); Origen Significado
Principio de
SEEK_SET
archivo
Posicion
SEEK_CUR actual
puntero
Final del
SEEK_END
archivo
31 ftell(f) long int stdio.h long int ftell(FILE *f); Devuelve la posicion actual ftell(fichen)
del puntero dentro del
archivo f
Escribe i2 elementos, cada
size_t fwrite(const void
fwrite(s, i1, uno de tamano 1 bytes,
32 int stdio.h *p, size_t i1, size_t i2, num=fwrite(lista,sizeof(char),25,flujo);
i2, f) desde la cadena s hasta el
FILE *f);
archivo f
while(c=getc(fx) !=EOF {
Lee un caracter del archivo
33 getc(f) int stdio.h int getc(FILE *f); print ("%c",c);
f
}
Lee un caracter desde el int c;
34 getchar( ) int stdio.h int getchar(void); dispostivo de entrada while((*c=getchar()) != '\n')
estandar print ("%c",c);
Lee una cadena de
caracteres desde el
35 gets(s) char(puntero) stdio.h char *gets(char *cad); gets(nombre);
dispositivo de entrada
estandar
Determina si el argumento carac=getch();
es alfanumerico. Devuelve if (isalnum(carac))
36 isalnum(c) int ctype.h int isalnum(int c); un valor disitinto de cero si print("%c letra|digito \n",carac);
es cierto; en otro caso else
devuelve 0 printf("%c no letra|digito \n", carac);
Determina si el argumento
es alfabetico. Devuelve un
int c;
37 isalpha(c) int ctype.h int isalpha(int c); valor distinto de cero si es
if (isalpha(c)) printf("%c es letra\n",c);
cierto; en otro caso
devuelve 0.
38 isascii(c) int ctype.h int isascii(int c); Determina si el argumento int c;
es un caracter ASCII. if (isascii(c)) printf('%c es un ascii\n",c)
Devuelve un valor disitinto
de cero si es cierto; en otro
caso devuelve 0
Determina si el argumento
es un caracter ASCII de
if(iscntrl(c)) printf"%c es un caracter de
39 iscntrl(c) int ctype.h int isacntrl(int c); control. Devuelve un valor
control\n",c);
distinto de cero si es cierto;
en otro caso devuelve 0
Determina si el numero es
un digito decimal. Devuelve
40 isdigit(c) int ctype.h int isdigit(int c); un valor disitinto de cero si if(isdigit(c)) printf"%c es un digito\n",c);
es cierto; en otro caso
devuelve 0
Determina si el argumento
es un caracter ASCII
grafico (hex 0x21 -0x7e;
if(isgraph(c)) printf"%c es un caracter
41 isgraph(c) int ctype.h int isgraph(int c); octal 041 -176). Devuelve
imprimible(no espacio)\n",c);
un valor distinto de cero si
es cierto; en otro caso
devuelve 0
Determina si el argumento
es ua minuscula. Devuelve
if(islower(c)) printf"%c es una letra
42 islower(c) int ctype.h int islower(int c); un valor distinto de cero si
minuscula\n",c);
es cierto; en otro caso
devuelve 0
43 isodigit(c) int ctype.h int isodigit(int c); Determina si el argumento if(isodigit(c)) printf"%c es un digito
es un digito octal. Devuelve octal\n",c);
un valor distinto de cero si
es cierto; en otro caso
devuelve 0
Determina si el el
argumento es un caracter
ASCII imprimible (hex
44 isprint(c) int ctype.h int isprintint c); 0x20 -0x7e; octal 040 if(isprint(c)) printf("\n"c imprimible\n",c);
-176). Devuelve un valor
distinto de cero si es cierto;
en otro caso devuelve 0
Determina si el argumento
es un caracter de
puntuacion. Devuelve un if(ispunct(c)) printf"%c es un caracter de
45 ispunct(c) int ctype.h int ispunct(int c);
valor distinto de cero si es puntuacion\n",c);
cierto; en otro caso
devuelve 0
Determina si el argumento
es un espacio en blanco.
46 isspace(c) int ctype.h int isspace(int c); Devuelve un valor distinto if(isspace(c)) printf"%c es un espacio\n",c);
de cero si es cierto; en otro
caso devuelve 0
Determina si el argumento
es una mayuscula.
if(isupper(c)) printf"%c es una
47 isupper(c) int ctype.h int isupper(int c); Devuelve un valor distinto
mayuscula\n",c);
de cero si es cierto; en otro
caso devuelve 0
48 isxdigit(c) int ctype.h int isxdigit(int c); Determina si el argumento ifisxdigit(c)) print"%c es un digito
es un digito hexadecimal. hexadecimal\n",c)
Devuelve un valor distinto
de cero si es cierto; en otro
caso devuelve 0
Devuelve el calor absoluto long lx=-51654,ly;
49 labs(l) long int math.h long int labs(long int l);
de 1 ly=labs(lx);
hdouble x,y;
Devuelve el logaritmo
50 log(d) double math.h double log(double d); x=10;
natural de d
y=log(x);
hdouble x,y;
Devuelve el logaritmno (en
51 log10(d) double math.h double log10(double d); x=10;
base 10) de d
y=log10(x);
Reserva u bytes de
memoria. devuelve un
52 malloc(u) void(puntero) stdlib.h void *malloc(size_t u); cadena=malloc(MAX_CHR);
puntero al principio del
espacio reservado
double pow(double d1, Devuelve d1 elevado a la double x=2.0, y=4.0, z;
53 pow(d1, d2) double math.h
double d2); potencia d2 z=pow(x,y); //z sera 1.60
Escribe datos en dispositivo
de salida estandar.
Codigo Formato
%c Caracter
int printf(const char
54 printf(...) int stdio.h Entero print("producto %d y %d es %d\n",x,y,x*y);
*formato[,argumento,...]); %d
Decimal
Real (double o
float),
%e
notacion
cientifica.
%f Coma flotante
Cadena de
%s
caracteres
Hexadecimal
%x
sin signo
Escribe un caracter en el
55 putc(c, f) int stdio.h int putc(int c, FILE *f); putc('*',demo);
archivo f
Escribe un caracter en el
56 putchar(c) int stdio.h int putchar(int c); dispositivo de salida putchar('B');
estandar
Escribe una cadena de
57 puts(s) int stdio.h int puts(const char *cad) caracteres en el dispositivo puts("Desea continuar (s/n);
de salida estandar
// visualizar 10 numeros aleatorios
Devuelve un entero positivo
58 rand( ) int stdlib.h int rand(void); for (i=0;i<10;i++)
aleatorio
printf("%6d\",rand());
Mueve el puntero al
59 rewind(f) void stdio.h void rewind(FILE *f); rewind(fx);
principio del archivo f
60 scanf(...) int stdio.h int scanf(const char Lee datos en dispositivo de scanf('%d %f %c %s, &i, &fp, &c, s);
*formato {,direccion,...]); entrada estandar
Codigo Formato
%c Caracter
%d Enetero
Decimal
%x Hexadecimal
Entero
%i
Decimal
%f Numero Real
%o Octal
%p Puntero
%s Cadena
double x, y;
x=0.52;
61 sin(d) double math.h double sin(double d); Devuelve el seno de d printf('x =%f radianes\n",x);
y=cos(x);
printf("el coseno de x =%f\n",y);
Devuelve el seno
62 sinh(d) double math.h double sinh(double d); y=sinh(x);
hiperbolico de d
Devuelve la raiz cuadrada
63 sqrt(d) double math.h double sqrt(double d); printf("%lf",sqrt(25.0); //se visualiza 5
de d
Inicializa el generador de
64 srand(u) void stdlib.h void srand(unsigned u); srand(semilla);
numeros aleatorios
65 strcmp(s1, int string.h int strcmp(const char*s1, Compara dos cadenas de i=strcmp("MNP", "mnp"); // resultado < 0
s2) const char *s2); caracteres i=strcmp("abc", "abc"); // resultado = 0
lexicograficamente. i=strcmp("xy", "abc"); // resultado > 0
Devuelve un valor negativo
si s1 < s2; 0 si s1 y s2 son char s1[80]="Mayo";
identicas; y un valor char s2[80]="Octubre";
positivo si s1 > s2 int j;
j=strcmp(s1,s2);
Compara dos cadenas de
caracteres
lexicograficamente, sin
strcmpi(s1, int strcmpi(const char*s1, diferenciar mayusculas de
66 int string.h v=strcmpi(s1,s2);
s2) const char *s2); minusculas. Devuelve un
valor negativo si s1 < s2; 0
si s1 y s2 son identicas; y
un valor positivo si s1 > s2