You are on page 1of 58

Programación en C

Índice
• Introducción: características, ventajas, desventajas, tipos de C.
• Estructura de un programa en C.
• Tipos de datos básicos. Conversiones de tipos. Constantes.
• Operadores y expresiones. Prioridad de los operadores.
• Sentencias condicionales: if, switch
• Sentencias repetitivas: while, do...while, for
• Sentencias break y continue
• Funciones y macros. Paso de parámetros por valor.
• Arrays y punteros. Strings: librería string.h. Paso de parámetros por
referencia.
• Gestión de memoria dinámica.
• Estructuras de datos: struct, union, enum, typedef.
• Declaración de variables: ámbito y tipo de almacenamiento.
• Entrada/Salida: librería stdio.h
• Librerías estándares de C: ctype.h, stdlib.h, math.h, time.h
• Desarrollo de programas: compilación separada, directivas al compilador.
• Resúmenes

Programación en C. Teoría 1 Dpto. ATC (UPV/EHU)


Introducción

Características
- Creado en 1972 por D. Ritchie en AT&T para desarrollar el sistema operativo UNIX.

- Lenguaje de nivel medio: elementos de un lenguaje de alto nivel combinados con la


funcionalidad de los lenguajes de bajo nivel.

- Diseñado para desarrollo de sistemas operativos. Hoy en día se usa para una amplia
gama de aplicaciones, sobre todo desarrollo de paquetes y librerías. Por ejemplo:
editores, paquetes de bases de datos, sistemas gráficos, etc.

Ventajas
* Lenguaje simple, con una potente librería estándar.

* Produce programas ejecutables muy eficientes y compactos.

* Lenguaje portable y abundancia de compiladores.

* Posibilidad de manejo directo de recursos físicos (bit, registros generales, direcciones


físicas, etc.), con lo que rara vez hay que recurrir al ensamblador.

Desventajas
* Programas crípticos e ilegibles si el programador no se esmera.

* No se produce verificación en tiempo de ejecución (índices de array, ...).

* En ausencia de declaración de tipos se interpreta tipo int.

* Necesidad de conocimiento y uso de debuggers y otras herramientas para depuración de


programas.

Tipos de C
* Fundamentalmente dos: C AT&T (o simplemente C) y ANSI C con pocas diferencias
entre ellos.

* C++ asimilable a lenguaje orientado a objetos.

Programación en C. Teoría 2 Dpto. ATC (UPV/EHU)


Estructura de un programa en C
/* Comentarios - no pueden anidarse */

// Comentario hasta final de línea- ANSI C

// includes de las librerías a utilizar


// definiciones globales

void f1() /* procedimiento definido por el usuario */


{
variables locales
sentencias del procedimiento
}

int f2() /* función definida por el usuario */


{
variables locales
sentencias de la función
}

...
...
...

char fN(int a, char *b, float c)


/* función con parámetros definida por el usuario */
{
variables locales
sentencias de la función
}

main () /* programa principal */


{
variables locales
sentencias del programa principal
}

int addition()
{
return(2+2);
}

main ( )
{
int n1, n2; /* declaración de variables */

n1=addition(); /* llamar a la función y recoger resultado*/


n2=n1/3;
}

Programación en C. Teoría 3 Dpto. ATC (UPV/EHU)


scanf / printf
#include <stdio.h>
main ( )
{
int r;
float area, perimetro;
printf ("Introduce el radio del círculo: \n");
scanf ("%d", &r); /* &->referencia */
area=3.14159*r*r;
perimetro=2*3.14159*r;
printf ("En un círculo de radio %d\n", r);
printf ("área: %f\n", area);
printf ("perímetro: %f\n", perimetro);
}

printf ("formato", expresión)


% reemplazar d número decimal
s cadena de caracteres (string) f número real
\n salto de línea c carácter

Tipos de datos básicos


TIPO NÚMERO DE RANGO REPRESENTACIÓN
BITS
void 0
char 8 caracteres ASCII
unsigned char 8 0/255
signed char 8 -128/127
int 16 ó 32*
unsigned int 16 ó 32*
signed int 16 ó 32*
short int 16 -32768/32767
unsigned short 16 0/65535
int
signed short int 16 -32768/32767
long int 32 -231/231-1
unsigned long int 32 0/232-1
signed long int 32 -231/231-1
float 32 Precisión de 7 cifras decimales
double 64 Precición de 15 cifras decimales
long double 128 Precición de 31 cifras decimales

Notas:
El fichero estándar <limits.h> contiene las definiciones de estos tipos básicos
Atención a la codificación UNICODE de caracteres
sizeof (tipo): devuelve el tamaño en bytes que ocupa el tipo de dato
Constantes

Programación en C. Teoría 4 Dpto. ATC (UPV/EHU)


Ejemplo Descripción
‘a’ carácter ‘a’
25 25 int
25L 25 long
25. 25 float
12.5 12.5 float
12.5E0 12.5 double (notación científica)
1.15E8 1.15*108 double
0123 123 octal = 83 int
0x53 53 hexadecimal = 83 int
“Curso de C” cadena de 10 caracteres

#include <stdio.h>
#define PI 3.14159
main ()
{
float r, area, perimetro;
printf ("Introduce el tamaño del radio\n");
scanf ("%f", &r);
perimetro = 2 * PI * r;
area = PI * r * r;
printf ("área: %f\n", area);
printf ("perimetro: %f\n", perimetro);
}

#include <stdio.h>
main()
{
int x1=10, y;
float x2=10.0;
y=4;
printf("%d %f", x1/y, x2/y);
}

Programación en C. Teoría 5 Dpto. ATC (UPV/EHU)


Conversiones de tipos

impícitas
char short

int

unsigned int

long

unsigned long

float

long double

casting: conversión de tipos explícita

#include <stdio.h>

main ( )
{
char car_min, car_may;
printf ("Introduce un carácter minúscula\n");
scanf ("%c", &car_min);
car_may = car_min – 'a' + 'A';
printf ("%c", car_may);
}

#include <stdio.h>

main ( )
{
char car_min, car_may;
printf ("Introduce un carácter minúscula\n");
scanf ("%c", &car_min);
car_may = (char)((int)car_min – (int)'a' + (int)'A');
printf ("%c", car_may);
}

Programación en C. Teoría 6 Dpto. ATC (UPV/EHU)


Operadores

Prioridad y asociatividad
OPERACIÓN OPERADOR ASOCIATIVIDAD
Paréntesis y corchetes () []. -> Hacia la derecha
Campo de estructuras
Negación
Incremento, decremento ! ~ ++ -- + - * &
Signo, Punteros (type) sizeof Hacia la izquierda
casting, sizeof
Producto, división, módulo * / % Hacia la derecha
Suma, resta + - Hacia la derecha
Deplazamiento >> << Hacia la derecha
< <= > >=
Comparación == != Hacia la derecha
&
^
Lógicas | Hacia la derecha
&&
Composición condicional || Hacia la derecha
Expresiones condicionales ? : Hacia la izquierda
= *= -= /= %=
Asignación &= |= ^= >>= <<= Hacia la izquierda

Operadores aritméticos
OPERACIÓN OPERADOR FORMATO DESCRIPCIÓN
Negación - -x Cambio de signo al valor de x
Suma + x+y x+y
Resta - x-y x-y
Producto * x*y x*y
División / x/y x/y
Módulo % x%y resto x/y
Incremento ++ x++ ++x x=x+1
Decremento -- x-- --x x=x-1

#include <stdio.h>

main()
{
int x=10, y=3;
printf("%d %d", x/y, x%y);
}

Programación en C. Teoría 7 Dpto. ATC (UPV/EHU)


Operadores
#include <stdio.h>

main()
{
int x, y, z=10;
float f,g;
printf("Introduce el valor de x:\n");
scanf("%d", &x);
f=x/z;
g=(float)x*z;
y++; // y=y+1; y+=1;
printf("f %f, g %f, y %d:\n", f, g, y);
y/=z; // y=y/z;
printf("ahora el valor de y es: %d\n", y);
}

Operadores lógicos
OPERACIÓN OPERADOR FORMATO DESCRIPCIÓN
AND & x&y x AND y
OR | x|y x OR y
XOR ^ x^y x XOR y
Negación lógica ~ ~x Cambian todos los bits de x
Desplazamiento a la Se desplazan y veces los
<< x << y
izquierda bits de x hacia la izda
Desplazamiento a la >> x >> y Se desplazan y veces los
derecha bits de x hacia la dcha

#include <stdio.h>

main()
{
short int x;
printf("Introduce el valor de x:\n");
scanf("%d", &x);
printf("Su complemento a uno es: %d.\n", ~x);
printf("Si el valor introducido no es negativo\n");
printf("se imprimirá un 0; en otro caso, no\n");
printf("%d\n", x & 0x80);
}

Programación en C. Teoría 8 Dpto. ATC (UPV/EHU)


Sentencias condicionales: if
Operadores relacionales
OPERACIÓN OPERADOR FORMATO DESCRIPCIÓN
si x>y TRUE (1)
Mayor > x>y
si no FALSE (0)
Menor < x<y si x<y TRUE (1)
si no FALSE (0)
si x==y TRUE (1)
Igual == x == y
si no FALSE (0)
Mayor o igual >= x >= y si x>=y TRUE (1)
si no FALSE (0)
si x<=y TRUE (1)
Menor o igual <= x <= y
si no FALSE (0)
si x!=y TRUE (1)
Distintos != x != y
si no FALSE (0)
si x eta y TRUE (1)
y && x && y
si no FALSE (0)
o || x || y si x edo y TRUE (1)
si no FALSE (0)
si x FALSE (0)
no ! !x
si no TRUE (1)

Notas:
• En las comparaciones por igual hay que utilizar == (y no =)
• (j!=0) y (j) son equivalentes, al igual que (j==0) y (!j)
• En los if-s anidados, la rama else se corresponde siempre con el último if escrito. En
caso de no ser así, hay que utilizar llaves.

#include <stdio.h>

main() /* mayor de dos números */


{
int a, b, mayor;
printf("Introduce dos números:\n");
scanf("%d", &a);
scanf("%d", &b);
if (a > b) // también { ins1; ins2;}
mayor = a;
else
mayor = b;
/* también: mayor = (a > b) ? a : b; */
printf ("El mayor entre %d y %d: %d", a, b, mayor);
}

Programación en C. Teoría 9 Dpto. ATC (UPV/EHU)


Sentencias condicionales: switch
#include <stdio.h>
main()
{
char c;
int a=10,b=5;
printf ("Introduce +, -, * ó /:\n");
scanf ("%c", &c);
switch (c)
{ case '+': printf ("%d\n", a+b);
break; // sin break, al siguiente case
case '-': printf ("%d\n", a-b);
break;
case '*': printf ("%d\n", a*b);
break;
case '/': printf ("%d\n", a/b);
break;
default: printf ("Signo erróneo\n");
break;
}
}

#include <stdio.h>
main()
{
char c;
printf("¿Vocal?\n");
scanf("%c", &c);
switch (c)
{ case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'A':
case 'E':
case 'I':
case 'O':
case 'U': printf ("Es vocal\n");
break;
default: printf ("No es vocal\n");
break;
}
}

Programación en C. Teoría 10 Dpto. ATC (UPV/EHU)


Sentencias repetitivas: while, do...while
#include <stdio.h>
main ()
{
char ch;
printf ("Introduce una letra\n");
ch=getchar();
while (ch!='a' && ch!='A')
{
switch (ch)
{
case '\n': break;
default: printf ("Has fallado\n");
}
ch=getchar();
}
printf ("Muy bien!!!");
printf ("Agur\n");
}

#include <stdio.h>
main ()
{
char ch;
printf ("Introduce una letra\n");
do
{
ch=getchar();
switch (ch)
{
case 'a':
case 'A': printf ("Muy bien!!!");
printf ("Agur\n");
break;
case '\n': break;
default: printf ("Has fallado\n");
}
}
while (ch!='a' && ch!='A');
}

Notas:
• Se puede utilizar la sentencia vacía como cuerpo del bucle:
while (cond){}; while (cond);
• Por ejemplo, para hacer un bucle infinito: while (1);

Programación en C. Teoría 11 Dpto. ATC (UPV/EHU)


Sentencias repetitivas: for
Notas:
• Funcionamiento de la sentencia for: for (a; b; c)
a.- Inicialización
b.- Evaluación de la condición:
si FALSE, fin del for
si TRUE, se ejecuta el cuerpo del for
c.- Actualización y vuelta al punto b
• Si no se evalúa ninguna condición, el bucle sería infinito, equivalente a while(1)
• Si no aparece ninguna inicialización ni actualización, for y while son equivalentes
• Las expresiones de la inicialización y actualización pueden ser compuestas:
for (x=0, y=10; x<y; x++, y--)

#include <stdio.h>
main ()
{
char ch;
int i;
printf ("Acierta la letra. 3 intentos\n");
for (i=1; i<=3; i++)
{
ch=getchar();
switch (ch)
{
case 'a': printf ("Muy bien!!!\n");
printf ("Agur\n");
exit();
case '\n': --i;
break;
default: printf ("Has fallado\n");
}
}
printf ("Lo siento\n");
for (i=0; i<1000; i++); /* for (; ; ;); */
printf ("Agur\n");
}

Programación en C. Teoría 12 Dpto. ATC (UPV/EHU)


Sentencias repetitivas: for
#include <stdio.h>

main()
{
int con, suma=0;
printf("Introduce los números a sumar\n");
scanf("%d", &con);
for (;con>=0 && con<=9;)
{
suma+=con;
scanf("%d", &con);
}
printf("%d",suma);
}

#include <stdio.h>

main()
{
char dato, mascara=0x01;
int i, cont=0;
printf("Introduce un carácter:\n");
scanf("%c",&dato);
for (i=0; i<8; i++)
{
if (dato & mascara) cont++;
mascara = mascara << 1;
}
printf("En el carácter %c (%x) hay %d unos\n",
dato, dato, cont);
}

Programación en C. Teoría 13 Dpto. ATC (UPV/EHU)


Sentencias break y continue
break: provoca el fin del bucle
continue: provoca el paso a la siguiente iteración del bucle

#include <stdio.h>
main () /* contar mayúsculas */
{
int i, cont=0;
char c;
printf("Introduce 80 caracteres\n");
for (i=0; i<80; i++)
{
scanf("%c", &c);
if (c>=’A’ && c<=’Z’) cont++;
if (c==’.’) break;
}
printf("Hemos contado %d mayúsculas\n",cont);
}

#include <stdio.h>
main ()
{
char c;
int a, b;
a=b=0;
scanf ("%c",&c);
while (c != '*')
{
if (c=='a' || c=='A')
{
a++;
scanf ("%c",&c);
continue;
}
if (c=='b' || c=='B') b++;
scanf ("%c",&c);
}
printf("Número de A’s:%d y número de B’s: %d\n",
a,b);
}

for (i = 0; i < 80; i++) {


scanf ("%c", &c);
if (c ==' ') continue;
if (c >= 'A' && c <= 'Z') cont ++;
if (c =='.') break;
}

Programación en C. Teoría 14 Dpto. ATC (UPV/EHU)


Funciones
Notas:
• La sentencia return indica el final de la función. Puede devolver un resultado; en caso de
no indicar nada, devuelve 0. Es habitual devolver –1 en caso de error. Sintaxis:
a.- return expresión;
b.- return (expresión);
c.- return;
• Si la función no devuelve ningún resultado se declara como void
• Los argumentos formales y los reales (utilizados en la llamada a la función) deben ser del
mismo tipo. Los argumentos se pueden pasar de dos formas:
a.- Por valor: no se modifican los parámetros reales
b.- Por referencia: se pasa como parámetro la dirección de la variable, por lo que
el parámetro real sí se puede modificar en la ejecución de la función
• Las variables locales se crean al comienzo de la función y se destruyen al finalizar la misma

Sintaxis de una función:

tipo_resultado nombre_función (parámetros formales)


{
/* declaración de variables locales */
/* cuerpo de la función */
}

tipo_resultado: void, int, char, char*, struct, ...

Ejemplo:
#include <stdio.h>

int cuadrado(int j)
{
j=j*j;
return(j);
}
main() /* ejemplo de paso de parámetros por valor */
{
int j=10;
printf("El valor %d es el cuadrado de %d\n", cuadrado(j), j);
}

Programación en C. Teoría 15 Dpto. ATC (UPV/EHU)


Funciones
#include <stdio.h>
long facto(int n) /* definición de la función */
{
long fact;
int i;
fact = 1;
i = 2;
while (i <= n) {
fact = fact * i;
i++;
}
return(fact);
}
main() /* primera versión de factorial */
{
int num;
printf("Introduce un número:\n");
scanf("%d", &num);
if (num<0) printf("Error: número negativo!\n");
else printf("El factorial de %d es %ld\n",num, facto(num));
}

#include <stdio.h>
main() /* segunda versión de factorial */
{
int num;
long facto(int n); /* prototipo de la función */
printf("Introduce un número:\n");
scanf("%d", &num);
if (num<0) printf("Error: número negativo!\n");
else printf("El factorial de %d es %ld\n",num, facto(num));
}
long facto(int n) /* definición de la función */
{
long fact;
int i;
fact = 1;
i = 2;
while (i <= n) {
fact = fact * i;
i++;
}
return(fact);
}

Programación en C. Teoría 16 Dpto. ATC (UPV/EHU)


Macros
Notas:
• No son funciones. La llamada a una macro no genera la ejecución de un subprograma. El
compilador sustituye cada llamada a una macro por el cuerpo de esa macro en tiempo de
compilación.
• Las macros no están sujetas a ningún tipo de datos.

#include <stdio.h>
#define PI 3.14159
#define area(rad) (PI*(rad)*(rad))
#define perimetro(rad) (2*PI*(rad))
main ( )
{
float r;
printf ("Introduce el tamaño del radio\n");
scanf ("%f", &r);
printf ("área: %f\n", area(r));
printf ("perimetro: %f\n", perimetro(r));
}

/* definición */
#define mayor(x,y) ((x)>(y) ? (x) : (y))
/* referencia */
res=mayor(num1, num2);
/* tras el preprocesado */
res=((num1)>(num2) ? (num1) : (num2))

Programación en C. Teoría 17 Dpto. ATC (UPV/EHU)


Arrays y punteros

1.- Declaración de arrays

- tipo nombre[dimensión];
- tipo nombre[filas][columnas];
- El índice del vector va desd 0 a (n-1)
- C no comprueba que el índice supere la dimensión del vector

int x[10];
int x[10] = {-1,4,6,-9,78,12,-34,0,-1,612};

char y[5];

int men[ ] = {1,2}; /* NO int men [ ]; */

int vector_2[2][5]={ {1,2,3,4,5}, {5,4,3,2,1} };


int vector_2[2][5]={1,2,3,4,5,5,4,3,2,1};
int vector_2[][5]={ {1,2,3,4,5}, {5,4,3,2,1} };
vector_2[2]=1; /* error */
vector_2=3; /* error */

2.- Declaración de punteros

OPERACIONES OPERADOR FORMATO DESCRIPCIÓN


Referencia & &x Dirección de x
Puntero * *p Dato apuntado por p
Vector [] x [i] Elemento i del vector x
Campo de una . x.y Campo y de la estructura x
estructura de datos -> p -> a Campo a de la estructura de datos
apuntada por p

En C los vectores y punteros están muy relacionados: el nombre de un vector es un


puntero al primer elemento del vector

Programación en C. Teoría 18 Dpto. ATC (UPV/EHU)


Arrays y punteros
int * pointr;
int x=10, y=0;
pointr=&x;
y=*pointr; /* y=10 */
*pointr=100;
y=(*pointr)+1; /* y=101*/
int *x[10];
int var=4;
x[2]=&var; /*printf ("%d", *x[2]);*/

/* Aritmética de punteros*/
char *p1; short *p2; long *p3;
p1++; p2++; p3++;
Aritmética de punteros: se pueden utilizar operadores aritméticos (++, +, -, --) y
relacionales (<, >, ==, <=, >= y !=). La unidad que se suma o resta depende del tamaño del
dato apuntado.

#include <stdio.h>

main ()
{
long total, ventas [12]; /* declaración del vector */
int i;
...
leer_vector (ventas, 12); /* por referencia */
for (i=0; i<12; i++)
total = total + ventas[i];
...

void leer_vector (long v[], int elementos)


{
int i;
for (i= 0; i < elementos; i++)
scanf ("%ld", &v[i]);
}

void leer_vector (long * v, int elementos)


{
int i;
for (i= 0; i < elementos; i++)
scanf ("%ld", &v[i]);
}

Programación en C. Teoría 19 Dpto. ATC (UPV/EHU)


Arrays y punteros
3.- Cadenas de caracteres (strings)
- Una cadena de caracteres es un vector cuyos elementos son caracteres. En C el
último carácter de una cadena es siempre el carácter de fin de string: '\0'
- La constante ‘\0’ se utiliza para detectar el fin del string.
- La librería estándar de C string.h contiene un conjunto de funciones para el manejo
de los strings

char y[5];
char y[5] = "agur";
char y[5] = {'a','g','u','r','\0'};

char x[5]="agur";
char *pointr;
pointr=x; /* printf("%c",*pointr); */
pointr++; /* *pointr='o'<=> x[1] */
char *men[]={"hola",“adios","agur", "kaixo"};
char **p;
p=&(men[2]); /* printf ("%s", *p); */
/* printf ("%c", **p); */

#include <string.h>

Función
char *strcat (char *s1, const char *s2) Añade el string s2 tras el string s1.
Modifica el string s1 y devuelve también
un puntero al nuevo string
char *strchr (const char *s, char c) Devuelve un puntero a la posición del
string s en el que se encuentra la primera
aparición del carácter c. Si el carácter no se
encuentra en el string devuelve NULL
int strcmp (const char *s1, const char *s2) Compara los strings s1 y s2. Devuelve 0 si
son iguales
char *strcpy (char *s1, const char *s2) Copia el string s2 en el string s1. Devuelve
un puntero al string s1
int strlen (const char *s) Devuelve el número de caracteres del
string s (sin incluir el carácter de fin de
string)
char *strncat Funciones idénticas a las anteriores strcat,
(char *s1, const char *s2, int n) strcpy y strcmp, pero que actúan sólo
char *strncpy sobre los primeros n caracteres de los
(char *s1, const char *s2, int n) strings correspondientes
int strncmp
(const char *s1, const char *s2, int n)

Programación en C. Teoría 20 Dpto. ATC (UPV/EHU)


Arrays y punteros: strings

#include <stdio.h>
#include <string.h>
#define MAX 30
char string2[]=”Operativos”;
int contcar(char *string, char car);
main()
{ char string1[]=”Sistemas”;
char string3[MAX];
strcpy(string3, string1);
strcat(string3, “ “);
strcat(string3, string2);
printf(“%d\n”, contcar(string3,’a’));
}

/* Cuenta el número de apariciones del carácter car


en el string */
int contcar(char * string, char car)
{
int cont =0, i;
for (i=0; string[i]!=’\0’; i++)
if (string[i]== car) cont ++;
return(cont);
}

/* contcar con punteros */


int contcar(char *string, char car)
{
int cont =0;
char *p;
for (p=string; *p!=’\0’; p++)
if (*p== car) cont ++;
return(cont);
}

Programación en C. Teoría 21 Dpto. ATC (UPV/EHU)


Arrays y punteros
4.- Funciones para la gestión de memoria dinámica  #include <stdlib.h>
Función Descripción
void * malloc (int tam) Reserva espacio en memoria para un objeto de tamaño tam.
Devuelve un puntero al espacio reservado, en caso de
problemas devuelve NULL (no hay espacio suficiente,
etc.). El espacio de memoria queda sin inicializar
void *calloc (int elem, int tam ) Reserva espacio en memoria para elem elementos de
tamaño tam (tamaño de un elemento en bytes). Devuelve
un puntero al espacio reservado, en caso de problemas
devuelve NULL. Inicializa a 0 el espacio de memoria
void *realloc (void *p, int tam) Cambia el tamaño del espacio apuntado por el puntero p al
tamaño tam. Reorganiza la memoria reservada previamente
con malloc, calloc o realloc, cambiando el tamaño de ese
espacio. Devuelve un puntero al espacio reservado.
void free (void *p) Libera el espacio de memoria apuntado por p, reservado
previamente con malloc, calloc o realloc.

#include <stdio.h>
#define MAX 1000
main ( )
{ int n,i;
int list [MAX];
printf ("¿Cuántos valores?:");
scanf ("%d",&n);
if (n>MAX)
{
printf("Error!\n");
exit(-1);
}
for (i=0; i<n; i++)
scanf ("%d",&list[i]);
}
/* utilizando memoria dinámica */
#include <stdio.h>
#include <stdlib.h>
main ( )
{ int n,i;
int * list;
printf ("¿Cuántos valores?:");
scanf ("%d",&n);
list = (int *) malloc (n*sizeof (int));
for (i=0; i<n; i++)
scanf ("%d", list+i);
}
Arrays y punteros: memoria dinámica
// producto de dos matrices
// dimensiones: m, n y p (se leen desde el teclado)
// C[m,p]=sumar(A[m,n]*B[n,p])

Programación en C. Teoría 22 Dpto. ATC (UPV/EHU)


#include <stdio.h>
#include <stdlib.h>
void leer_matriz (float **M, int filas, int col);
void print_matriz (float **M, int filas, int col);
void borrar_matriz (float **M, int filas)
{
int i;
for (i=0;i<filas;i++) free(M[i]);
free(M);
}
main ()
{
int m,n,p,i,j,k;
float **A, **B, **C; /* memoria dinámica */
printf (“Introduce las dimensiones m,n y p\n”);
scanf (“%d %d %d”,&m,&n,&p);
A= (float **) malloc (m*sizeof (float*));
for (i=0;i<m;i++) A[i]=(float *) malloc (n*sizeof(float));
B= (float **) malloc (n*sizeof (float*));
for (i=0;i<n;i++) B[i]=(float *) malloc (p*sizeof(float));
C= (float **) malloc (m*sizeof (float*));
for (i=0;i<m;i++) C[i]=(float *) malloc (p*sizeof(float));

leer_matriz(A,m,n);
leer_matriz(B,n,p);
for (i=0; i<m; i++)
for(j=0; j<p; j++)
{
C[i][j]=0;
for(k=0; k<n; k++)
C[i][j]= C[i][j]+A[i][k]*B[k][j];
}
print_matriz(C,m,p);
borrar_matriz(A,m);
borrar_matriz(B,n);
borrar_matriz(C,m);
}

Programación en C. Teoría 23 Dpto. ATC (UPV/EHU)


Arrays y punteros
5.- Parámetros por referencia
void main()
{ int a , b;
printf(“Introduce dos valores\n”);
scanf(“%d %d”, &a, &b);
intercambiar (&a, &b); /* por referencia  @ variables */
printf (“%d %d\n”, a, b);
}

void intercambiar (int *x, int *y)


/* los parámetros son punteros */
{
int tmp; /* variable local */
tmp = *x; *x = *y;*y = tmp;
}

6.- Parámetros de la función main


- int argc: indica el número de parámetros que se reciben
- char *argv[]: es un vector de strings. Cada string es un parámetro que
recibe la función main. El primer parámetro, argv[0], es siempre el nombre
del programa
void main(int argc, char * argv[])
/*vector de strings */
{
printf("nombre del programa:%s\n",argv[0]);
for (int i=1; i<argc; i++)
printf("argumentos %d:%s\n",i,argv[i]);
}

#include <stdio.h>
#include <stdlib.h>
long facto (int n)
{
long res; int i;
for (i=1, res=1; i<=n; i++) res*=i;
return(res);
}
void main (int argc, char *argv[])
{
int num;long factorial;
num = atoi(argv[1]);
factorial = facto(num);
printf (“El factorial de %d es %ld\n”,
num,factorial);
}

Programación en C. Teoría 24 Dpto. ATC (UPV/EHU)


Arrays y punteros
7.- Punteros a funciones
La función representa en una dirección de memoria que se puede asignar a un
puntero. La dirección de la función es el punto de entrada de la función y se puede
utilizar para llamar a la función.

#include <stdio.h>

void main ()
{
int y, x=5;
int (*funcion)(int);
int pot2(int);
int pot3(int);
funcion=pot2;
y=funcion(x);
printf("%d al cuadrado: %d\n",x,y);
funcion=pot3;
y=funcion(x);
printf("%d al cubo: %d\n",x,y);
}

int pot2 (int x)


{
return (x * x);
}

int pot3 (int x)


{
return (x * x * x);
}

Programación en C. Teoría 25 Dpto. ATC (UPV/EHU)


Estructuras de datos
1.- Estructuras (struct)
- La definición de una estructura se realiza en dos fases: primero se definen los
campos que forman parte de la estructura, y a continuación se define una variable
de esa estructura.
- Para definir estructuras se utiliza la palabra clave struct.

struct libro struct libro struct


{ { {
int cod; int cod; int kod;
int preciov; int preciov; int preciov;
}; }lib; }lib;
struct libro lib;

# include <stdio.h>
# include <string.h>
struct libro
{
int cod;
int preciov;
char titulo[30];
};
/* función para leer los datos de un libro */
int leer_lib ( struct libro *plib)
{
char aux2[30];
int aux1;
printf(“\n\n código del libro: \n”);
scanf(“%d”, &aux1);
plib->cod=aux1;
if (plib->cod>=0)
{
printf(“título del libro: \n”);
scanf(“%s”, aux2);
strcpy(plib->titulo, aux2);
printf(“precio de venta del libro: \n);
scanf(“%d”, &aux1);
plib->preciov=aux1;
}
return(plib->cod);
}

Programación en C. Teoría 26 Dpto. ATC (UPV/EHU)


Estructuras de datos: struct
void print_libro (struct libro *plib)
{
printf ("%d %s %d \n",plib->cod,
plib->titulo, plib->preciov);
// plib->cod y (*plib).cod es el mismo acceso
}

void print_lib (int min, int max)


{
struct libro lib; /* variable de tipo libro */
int cod-fin;
cod-fin = leer_lib(&lib);
while (cod-fin > = 0)
{
if ((lib.preciov<=max)&&(lib.preciov>=min))
printf(“%d %s %d \n”,lib.cod, lib.titulo,
lib.preciov);
cod-fin = leer_lib (&lib);
}
}

#define MAX 40
#define NMAX 20
struct nodo {
char nombre [MAX];
struct nodo *izda, *dcha;
};
struct nodo arbol[NMAX]; /* vector de estructuras */

void print_arbol(struct nodo *pnodo)


{
if (pnodo!=NULL){
print_arbol(pnodo->izda);
printf("%s\n", pnodo->nombre);
print_arbol(pnodo->dcha);
}
}

Programación en C. Teoría 27 Dpto. ATC (UPV/EHU)


Estructuras de datos
2.- Campos de bits
struct dispositivo {
unsigned activado: 1;
unsigned listo: 1;
unsigned error: 1;
unsigned operacion: 4;
}cdis;

......

void inicializar_escritura ()
{
cdis.activado=1;
cdis.listo=1;
cdis.error=0;
cdis.operacion=3;
}
byte
0 cdis.activado
1 cdis.listo
2 cdis.error
3
4
cdis.operacion
5
6
7 sin uso

3.- Enumerados (enum)


enum semana {lunes, martes, miercoles, jueves,
viernes, sabado, domingo};
long tarifa (enum dia, long tar1, long tar2)
{
switch (dia){
case sabado:
case domingo: return (tar2);
default: return (tar1); }
}
4.- Sinónimos
typedef short bool; /* bool es sinónimo de short */
bool and_logica (bool a, bool b)
{
return (a&b);
}

Programación en C. Teoría 28 Dpto. ATC (UPV/EHU)


Estructuras de datos
5.- Uniones (union)
union numero{
int entero;
double real;
char string[16];
};

int main()
{
union numero dato;
printf(“El tamaño de un int es %d\n”, sizeof(int));
printf(“El tamaño de un double es %d\n”, sizeof(double));
printf(“El tamaño de un char[16] es %d\n”,
sizeof(char[16]));
printf(“El tamaño del union es %d\n”,
sizeof(union numero));
dato.entero = 8;
printf(“El valor entero del union es %d\n”,dato.entero);
dato.real = 8.24;
printf(“El valor real del union es %f\n”,dato.real);
strcpy(dato.string, “8.24132”);
printf(“El valor del string del union es %s\n”,
dato.string);
return(0);
}

struct fecha
{
char dia[2];
char mes[2];
char anyo[4]
};

union fecha_facil
{
char fecha1[8];
struct fecha fecha2;
};

Programación en C. Teoría 29 Dpto. ATC (UPV/EHU)


Declaración de variables

interno register
static
extern

externo static
extern

tipo_almac. tipo_dato nombre inicializacion

void escalares estructurados

puntero char num. enum


string array struct union bits
enteros reales

int long short float double

Ámbito

Programa

Fichero fuente

Función

Bloque

Tipo de almacenamiento
Register. La variable se almacena en los registros internos del procesador. Se utiliza para
variables de tipo int o char, y sólo dentro de un bloque

Static. Para variables definidas fuera de una función (globales) limita su ámbito al fichero en
el que están definidas. En el caso de variables definidas dentro de una función (locales), hace
que el tiempo de vida de la variable sea permanente.

Extern. Cuando se quiere utilizar una variable definida fuera del módulo de compilación, hay
que definir esa variable en el módulo como externa, indicando que su definición está fuera del
módulo actual.

Programación en C. Teoría 30 Dpto. ATC (UPV/EHU)


Declaración de variables
int var_global=-1; /* variable global */

main (int argc, char *argv[])


{
int i, j, k; /* variables locales */
struct tipo_local
{
int k;
int j;
} var_local[MAX];

……………………

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


{
int k=5; /* variable local */
………
}
var_global--;
}

int desde_aqui=0; /* variable global */

void funcion_desde_aqui()
{
desde_aqui++;
var_global++;
}

#include <stdio.h>

int j=10; /* definida para todo el programa */

int f1()
{
int j=0; /* definida para la función */

for (;j<3;j++) printf(“j: %d\t”,j);


}

main ()
{
f1();
printf(“J: %d”,j);
}

Imprimirá: j: 0 j: 1 j: 2 J: 10

Programación en C. Teoría 31 Dpto. ATC (UPV/EHU)


Declaración de variables
char *n_mes[]={"error","enero","febrero","marzo",
"abril","mayo","junio","julio",
"agosto", "setiembre", "octubre",
"noviembre", "diciembre"};

char * nom_mes(int n)
{
return (((n<1) || (n>12))?n_mes[0]:n_mes[n]);
}

char * nom_mes(int n)
{
static char * n_mes[]={"error",
"enero", "febrero", "marzo",
"abril", "mayo", "junio", "julio",
"agosto", "setiembre", "octubre",
"noviembre", "diciembre"};
return (((n<1) || (n>12))?n_mes[0]:n_mes[n]);
}

/*Con variables static son válidas las inicializaciones


static char c[5]="hola";
dentro de funciones */

#include <stdio.h>

void funcion1 ()
{
static int k=5;

k++;
printf (“k: %d\t”,k);
}

main ()
{
int k=-1;

for (int i=0;i<3;i++) funcion1();

printf (“K: %d\n”,k);


}

Imprimirá: k: 6 k: 7 k: 8 K: -1

Programación en C. Teoría 32 Dpto. ATC (UPV/EHU)


Declaración de variables
/* fichero pila.c */

#define MAXVAL 100 /*profundidad máxima de la pila*/

static int sp=0; /*apuntador de la pila*/


static double val [MAXVAL]; /*pila*/

double push(double f) /*introduce f en la pila*/


{
if (sp<MAXVAL)
return (val[sp++]=f);
else{
printf("error: stack full\n");
return (0);
}
}

double pop () /*extrae el elemento superior de la pila*/


{
if (sp>0)
return (val [--sp]);
else{
printf ("error: stack empty\n");
return (0);
}
}

void clear() /*limpia la pila*/


{
sp=0;
}

Variables CONST

Garantiza que el valor de la variable no se modificará después de su inicialización. Su objetivo


es asegurar que no se modifican variables que se suponen de solo lectura.

const char cadena[100]=”Este string no se puede modificar!!!”

int var1=19; /* se puede modificar */


int *const var2=&var1; / el puntero var2 no se puede modificar */

Programación en C. Teoría 33 Dpto. ATC (UPV/EHU)


Entrada/Salida (#include <stdio.h>)
1.- E/S por caracteres: printf (sprintf)

int printf (char *formato, lista_argumentos_valor)


Imprime por la salida estándar (stdout) la lista de argumentos formateada de acuerdo al string
de formato. La lista de argumentos está compuesta de expresiones separadas por comas.
Devuelve un valor negativo si hay error y, en caso contrario, devuelve el número de
caracteres escritos.

El string de formato contiene dos tipos de objetos:


- caracteres ordinarios: que sencillamente se copian en la salida estándar,
- especificadores de conversión: originan la conversión e impresión del siguiente
argumento de la lista de argumentos. Cada especificación de conversión comienza con el
carácter % y acaba en un carácter de conversión. En medio puede haber un modificador.
% [modificador] carácter de conversión
Si el carácter que sigue al % no es ninguno de los indicados como caracteres de conversión,
dicho carácter se imprime tal cual.

Caracteres de conversión:
d,i Conversión a decimal con signo (int)
o El argumento se convierte a notación octal (int)
x,X Conversión a notación hexadecimal sin signo. (int)
u Conversión a entero decimal sin signo (unsigned int)
c El argumento se imprime como un carácter (char)
s El argumento es un string de caracteres (char *). Se imprimen los caracteres del
string hasta encontrar el carácter ‘\0’ de fin de string o hasta alcanzar el número de
caracteres indicado como precisión.
f Conversión a coma flotante con formato [-]mmm.nnnnnn (double). La precisión
por defecto es 6.
e,E Conversión a coma flotante con signo en notación [-]m.nnnnnnE[±]xx (double). La
precisión por defecto es 6.
g,G Emplea el más corto de %e o %f (double). Se usa %f, salvo si el exponente es
menor que –4
p Imprime en hexadecimal el valor de un puntero (void *)

Programación en C. Teoría 34 Dpto. ATC (UPV/EHU)


Modificadores [%flagsanchura.precisionhlLcarácter_conversión]
flags Por defecto, el argumento se imprime justificado a la derecha. Se puede cambiar la
forma de imprimir un argumento teniendo en cuenta los siguientes flags.
- justifica a la izquierda + imprime siempre el signo del número
espacio imprime un espacio si el primer carácter no es un signo
0: rellena a ceros el número
# imprime con 0, 0x, 0X en el caso de o, x, X
mantiene el punto decimal en e, E, f, g, G
no elimina los ceros por detrás en g, G
anchura El argumento se imprime como mínimo con la anchura indicada por este valor. Si
es necesario se rellena el campo hasta conseguir esa anchura
punto Se utiliza para separar la anchura y la precisión
precisión Indica el máximo número de caracteres a imprimir si se trata de un string, el
mínimo número de dígitos si se trata de un entero o el mínimo número de
dígitos decimales para un valor real
hlL El carácter h, l o L se combina con el carácter de conversión para indicar la conversión
a realizar a la hora de imprimir ese argumento: h para short o unsigned short, l para
long o unsigned long y L para long double.

Por ejemplo, dada la variable char *s=”hello, world”(12 caracteres), a continuación se


muestran varios ejemplos de posibles impresiones de esa variable de acuerdo a los
modificadores utilizados. Se ha marcado con el carácter ‘:’ los límites del campo impreso.

%s :hello, world: %-10s :hello, world:


%10s :hello, world: %-15s :hello, world :
%.10s :hello, wor: %15.10s : hello, wor:
%.15s :hello, world: %-15.10s :hello, wor :

También se puede indicar la anchura o la precisión con el carácter ‘*’. Esto indica que éste
número se proporciona como argumento:

double valor;
int anchura, precision;
printf (“%*.*f”,anchura,precision,valor);

Otros caracteres importantes:


\' comilla simple \" comillas dobles \\ barra invertida
\n nueva línea \t tabulación horizontal

int sprintf (char *s, char *formato, lista_argumentos_valor)


Similar a printf, pero en lugar de imprimir en la salida estándar, crea un string s de acuerdo al
formateo de los argumentos proporcionados.

Programación en C. Teoría 35 Dpto. ATC (UPV/EHU)


Entrada/Salida
2.- E/S por caracteres: scanf (sscanf)
int scanf (char *formato, lista_argumentos_referencia)
Lee caracteres desde la entrada estándar (stdin), los formatea de acuerdo a la especificación
de la lista de argumentos y almacena los resultados en las variables indicadas como
argumento (todos las variables deben ser punteros, variables por referencia). Finaliza cuando
se ha acabado de procesar la lista de argumentos (devuelve el número de argumentos
procesados), si se llega al fin de entrada (devuelve EOF, -1) o si no hay concordancia entre la
entrada y el tipo de argumento a leer (devuelve 0).

El string de formato puede contener:


- blancos, tabuladores o fines de linea: que no se tienen en cuenta.
- especificadores de conversión: formado por:
a) el carácter %
b) un carácter opcional de suspensión de asignación (el carácter ‘*’). El siguiente
campo no se asigna a ninguna variable
c) un número opcional que indica el tamaño máximo del campo
d) el carácter h o l, para indicar short o long (debe preceder a d, i, o, u, x), o el
carácter l o L para indicar double o long double (sólo para e, f, g)
e) el carácter de conversión.
% [* ] [n] [hlL]carácter de conversión

Caracteres de conversión:
d,i se espera un número decimal a la entrada. Argumento int *
o se espera un entero octal (con o sin 0 a la izquierda). Argumento int *
x,X se espera un entero hexadecimal (con o sin ceros a la entrada). El argumento debe
ser int *
u conversión a entero decimal sin signo (unsigned int *)
c lee y asigna uno (por defecto) o más caracteres (incluye espacio en blanco).
Argumento char *
s lee y asigna un string de caracteres (con el \0). El argumento debe ser char*
e,f,g se espera un número en coma flotante, en notación de punto fijo [-]mmm.nnnnnn o
científica [-]m.nnnnnnE[±]xx. El argumento debe ser float *
Entrada: 25 enero 2005
int dia, anno;
char mes[20];
scanf (“%d %s %d”,&dia,mes,&anno); // salta los blancos

int sscanf (char *s, char *formato, lista_argumentos_referencia)


Similar a scanf, pero en lugar de leer desde la entrada estándar, procesa los caracteres desde el
string s pasado como parámetro.

Programación en C. Teoría 36 Dpto. ATC (UPV/EHU)


Entrada/Salida
3.- Otras funciones de E/S por caracteres: getchar, putchar, gets, puts

Función Descripción
int getchar () Lee el siguiente carácter de la entrada estándar, convertido en int
int getch()
int putchar (int c) Imprime el carácter c en la salida estándar
char *gets (char *s) Lee la siguiente línea de la entrada estándar en s. Reemplaza ‘\n’
por ‘\0’. Devuelve s o NULL (error o EOF)
int puts (const char *s) Escribe el string s en la salida estándar. Sustituye ‘\0’ por ‘\n’.
Devuelve un valor no negativo si no hay error o EOF si error.

#include <stdio.h>

int leer_linea (char *linea)


{
int c, i=0;

do {
c=getchar(); // conversión char --> int
linea[i]=c; // conversión int --> char
i++;
}
while ((c!=’\n’) && (c!=EOF));
linea[i]=’\0’; // fin de string
return (i);
}

#include <stdio.h>

int leer_linea (char *linea)


{
int i;

gets(linea);
for (i=0; linea[i]!=’\0’; i++); // sin cuerpo
return (i+1);
}

Programación en C. Teoría 37 Dpto. ATC (UPV/EHU)


Entrada/Salida
4.- E/S con ficheros: fopen y fclose

FILE* fopen (const char * nombre_fichero, const char *modo)


Abre el fichero especificado (nombre_fichero) en el modo indicado (modo). Devuelve un puntero al
fichero (FILE*) si todo ha sido correcto o NULL si ha habido algún problema.

int fclose (FILE *fp)


Cierra el fichero especificado por el descriptor fp Devuelve EOF en caso de error y 0 en caso
contrario.

Modo Descripción Posición puntero


“r” lectura (error si no existe) comienzo
“w” escritura comienzo
(si el fichero existe, borra su contenido)
“a” escritura al final (append) final fichero
(si no existe, lo crea)
“r+” lectura + escritura (error si no existe) comienzo
“w+” lectura + escritura comienzo
(si el fichero existe, borra su contenido)
“a+” lectura + escritura al final (append) final fichero

Función Descripción
int fprintf (FILE *fp, Similar a printf, con salida a un fichero
char *formato, lista_argumentos_valor)
int fscanf (FILE *fp, Similar a scanf, con entrada desde un fichero
char *formato, lista_argumentos_ref)
char *fgets (char *s, int n, FILE *fp) Lee una cadena de n-1 caracteres desde el fichero
sobre el string s. Acaba si encuentra ‘\n’ o EOF.
Añade al string el carácter ‘\0’. Devuelve s o NULL
si ha habido error
int fputs (const char *s, FILE *fp) Similar a puts, con salida a un fichero.
int getc (FILE *fp) Devuelve el siguiente carácter del fichero, convertido
int fgetc (FILE *fp) en int. Si fin de fichero o error, devuelve EOF
int putc (int c, FILE *fp) Escribe el carácter c convertido en char en el fichero.
int fputc (int c, FILE *fp) Devuelve c o EOF en caso de error
int ungetc (int c, FILE *fp) Devuelve el carácter c (en principio, el último leído
previamente mediante getc) al fichero. La siguiente
lectura vuelve a leer el mismo carácter c
int feof (FILE *fp) Devuelve TRUE (!=0) si una lectura o escritura
previa han llegado a fin de fichero
int fflush (FILE *fp) Fuerza el almacenamiento del buffer en el fichero
FILE * tmpfile () Crea un fichero temporal en escritura. El fichero se
borra automáticamente en fclose o al acabar el
programa

Programación en C. Teoría 38 Dpto. ATC (UPV/EHU)


Entrada/Salida
#include <stdio.h>
#define MAX 80
main ()
{
FILE *infile, *outfile;
char f1[20],f2[20],palabra[MAX];
int total_palabra;
printf ("\nIntroduce el fichero de lectura: ");
scanf ("%s",f1);
infile=fopen(f1,"r");
printf ("\nIntroduce el fichero de salida: ");
scanf ("%s",f2);
outfile=fopen(f2,"w");
while (fscanf(infile,"%s",palabra)!= EOF)
{
total_palabra=strlen(palabra);
fprintf(outfile,"%d %s\n",total_palabra,palabra);
}
fclose(infile);
fclose(outfile);
}

#include <stdio.h>
#define MAX 80
main ()
{
FILE *infile, *outfile;
char f1[20],f2[20],linea[MAX];
int total_linea;
printf ("\nIntroduce el fichero de lectura: ");
scanf ("%s",f1);
infile=fopen(f1,"r");
printf ("\nIntroduce el fichero de salida: ");
scanf ("%s",f2);
outfile=fopen(f2,"w");
while (fgets(linea,MAX,infile)!= NULL)
{
total_linea=strlen(linea);
fprintf(outfile,"%d %s\n",total_linea,linea);
}
fclose(infile);
fclose(outfile);
}

Programación en C. Teoría 39 Dpto. ATC (UPV/EHU)


Entrada/Salida
5.- E/S binaria: fread y fwrite
int fread (void *p, int lon, int num_elem, FILE *fp)
Lee del fichero un bloque de num_elem elementos, cada uno de los cuales tiene de longitud lon
bytes. Almacena el bloque leído en el espacio apuntado por el puntero p. La función acabará cuando
se lea el bloque, se llegue a fin de fichero u ocurra algún error. En cualquier caso, devuelve el
número de elementos leídos.

int fwrite (void *p, int lon, int num_elem, FILE *fp)
Escribe en el fichero un bloque de num_elem elementos de tamaño lon bytes cada uno, almacenados
en el espacio apuntado por p. Devuelve el número de elementos escritos (num_elem salvo que haya
existido algún error).

#include <stdio.h>

main(int argc, char *argv[])


{
FILE *infile,*outfile;
char buffer[200];
int lon;
-------
do {
lon=fread(buffer,1,200,infile);
fwrite(buffer,1,lon,outfile);
}
while(lon==200);
}

6.- Acceso directo: fseek


int fseek (FILE *fp, long num_bytes, int origen)
Posiciona el fichero en num_bytes a partir del origen indicado. Devuelve 0 si la operación ha sido
correcta. Posibles valores para el origen:
SEEK_SET: posición respecto al principio del fichero
SEEK_CUR: posición respecto a la posición en curso
SEEK_END: posición respecto al fin de fichero

long ftell (FILE *fp)


Devuelve el número de bytes desde el comienzo del fichero hasta la posición actual, es decir,
devuelve la posición actual dentro del fichero. En caso de error, devuelve –1.

void rewind (FILE *fp)


Sitúa la posición del fichero al comienzo del fichero.

Programación en C. Teoría 40 Dpto. ATC (UPV/EHU)


Entrada/Salida
// programa cp  cp f1 f2
# include <stdio.h>
# define SALTO 10L
# define TAM 50
void error(int tipo);
main ()
{
FILE *fentrada, *fsalida;
char buffer[TAM];
int n;
if ((fentrada=fopen("fich1.c","r"))==NULL) error(1);
if ((fsalida=fopen("fich2.c","w"))==NULL) error(1);
if (fseek(fentrada,SALTO,SEEK_SET)!=0) error(2);
while ((n=fread(buffer,sizeof(char),TAM,fentrada))!=0)
if (fwrite(buffer,sizeof(char),n,fsalida)!=n) error(3);
if (!feof(fentrada)) error(4);
if (fclose(fentrada)==EOF) error(5);
if (fclose(fsalida)==EOF) error(5);
}

// programa cat  cat f1 f2 f3


#include <stdio.h>
void volcar_fichero (FILE *file)
{ char c;
do {
c = fgetc (file);
fputc (c, stdout);
}
while (c!= EOF);
}
main (int argc, char *argv[])
{ FILE *fp;
int i;
if (argc < 2) volcar_fichero(stdin);
else
for (i=1; i<argc; i++){
fp = fopen (argv [i], "r");
if (fp == NULL)
{ fprintf (stderr,"error al abrir\n");
exit (1);}
else volcar_fichero (fp);
fclose (fp); }
exit (0);
}
Entrada/Salida
struct libro {

Programación en C. Teoría 41 Dpto. ATC (UPV/EHU)


int cod;
char titulo[30],autor[30];
int precio;
};

#define TOPE 10

void escribirf_libros (char *nombref)


{
struct libro unlibro;
FILE *fd;
int i;
fd=fopen(nombref,”wb”);
for (i=0;i<TOPE;i++)
{
printf (“Introduce el código del libro: \n”);
scanf (“%d”,&(unlibro.cod));
printf (“Introduce el título y autor del libro: \n”);
scanf (“%s %s”,unlibro.titulo, unlibro.autor);
printf (“Introduce el precio del libro: \n”);
scanf (“%d”,&(unlibro.precio));
printf (“Datos introducidos: %d\t%s\t%s\t%d\n”,
unlibro.cod, unlibro.titulo,
unlibro.autor, unlibro.precio);
fwrite (&unlibro,sizeof(struct libro),1,fd);
}
fclose(fd);
}

void leerf_libros (char *nombref)


{
struct libro unlibro;
FILE *fd;
int i;
fd=fopen(nombref,”rb”);
for (i=0;i<TOPE;i++)
{
fread (&unlibro,sizeof(struct libro),1,fd);
printf (“Datos leídos: %d\t%s\t%s\t%d\n”,
unlibro.cod, unlibro.titulo,
unlibro.autor, unlibro.precio);
}
fclose(fd);
}

Programación en C. Teoría 42 Dpto. ATC (UPV/EHU)


Entrada/Salida
#include <stdio.h>
#include <ctype.h>

main(int argc, char *argv[])


{
FILE *update;
int fpos;
char c;
if((update=fopen(argv[1],”r+”))==NULL)
{
fprintf(stderr,”%s: error al abrir %s\n”,
argv[0],argv[1]);
exit(-1);
}
while ((c=fgetc(update))!=EOF)
{
if (isupper(c))
{
fpos=ftell(update);
fseek(update,fpos-1,SEEK_SET);
fputc(tolower(c), update);
}
/* OTRA POSIBILIDAD
if (isupper(c))
{
ungetc(c,update);
fputc(tolower(c), update);
}
*/
}
fclose(update);
}

Programación en C. Teoría 43 Dpto. ATC (UPV/EHU)


Librerías estándares de C
1.- Funciones para el manejo de caracteres  #include <ctype.h>

Función Descripción
int tolower (int car) Si car es un carácter mayúscula, devuelve su correspondiente
minúscula. En otro caso, devuelve car
int toupper (int car) Si car es un carácter minúscula, devuelve su correspondiente
mayúscula. En otro caso, devuelve car
int islower (int car) True si car es minúscula
int isupper (int car) True si car es mayúscula
int isalpha (int car) True si islower (car) o isupper (car)
int isdigit (int car) True si car es dígito decimal
int isalnum (int car) True si isalpha (car) o isdigit (car)
int iscntrl (int car) True si car es un carácter de control
int isspace (int car) True si car es SPACE, \f, \n, \r, \t, \v

#include <ctype.h>
#include <stdio.h>

main()
{ char car;
int num, i;

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


{ printf("Introduce un carácter:");
scanf("%c", &car);
if (isdigit((int)car))
printf("%c es numérico\n", car);
else
if (!isalpha((int)car))
printf("%c no es ni letra ni numérico\n", car);
else
if (islower((int)car))
{ num=toupper((int)car);
printf("El carácter mayúscula de %c es %c\n",
car,(char)num);
}
else
{ num=tolower((int)car);
printf (“El carácter minúscula de %c es %c \n", car,
(char)num);
}
}
}

Programación en C. Teoría 44 Dpto. ATC (UPV/EHU)


Librerías estándares de C
2.- Funciones para conversión de números  #include <stdlib.h>

Función Descripción
double atof (const char *s) Convierte a double la cadena de caracteres apuntada por s
int atoi (const char *s) Convierte a int la cadena de caracteres apuntada por s
long atol (const char *s) Convierte a long la cadena de caracteres apuntada por s
int abs (int num) Devuelve el valor absoluto de num (entero)
long labs (long num) Devuelve el valor absoluto de num (long)

3.- Funciones para la ejecución/fin de programas  #include <stdlib.h>

Función Descripción
void exit (int estado) Provoca la finalización del programa, el parámetro indica
cómo acaba el programa (0  éxito)
int system (const char *comando) Lanza la ejecución del comando indicado por el string
comando
char * getenv (const char * var) Devuelve el valor de la variable de entorno asociada al
string var, o NULL si no está definida

#include <stdlib.h>
#include <stdio.h>

double calcular (int par1, double par2);

main(int argc, char *argv[])


{
int num1;
double res,num2;

if (argc !=3)
{
printf (“Error en parámetros. Programa: %s\n”,argv[0]);
exit(-1);
}
res = calcular (atoi(argv[1]),atof(argv[2]));
printf(“El resultado es: %.4f\n”,res);
}

4.- Funciones para la generación de números aleatorios  #include <stdlib.h>

Función Descripción
int rand () Devuelve un valor entero aleatorio, entre los valores 0 y
RAND_MAX (constante definida en stdlib.h)
void srand (unsigned int semilla) Utiliza semilla como valor de comienzo de una secuencia
de números aleatorios. Si no se llama a srand antes que a
rand, el valor de comienzo siempre es 1

Programación en C. Teoría 45 Dpto. ATC (UPV/EHU)


Librerías estándares de C
5.- Funciones para el manejo de objetos en memoria  #include <string.h>

Función Descripción
void * memcpy Copia en el objeto apuntado por p1 n caracteres desde el
(void *p1, const void *p2, int n) objeto apuntado por p2. Devuelve un puntero al objeto
apuntado por p1
void * memmove Igual que memcpy, pero también funciona aunque los dos
(void *p1, const void *p2, int n) objetos se solapen
void * memset Inicializa los n primeros caracteres del objeto apuntado por
(void *p, int car, int n) p con el carácter car. Devuelve un puntero al objeto
apuntado por p
int memcmp (const void *p1, Compara los n primeros caracteres de los objetos
const void *p2, int n) apuntados por p1 y p2. El resultado devuelto es idéntico al
de la función strcmp
void * memchr Devuelve un puntero a la primera ocurrencia del carácter
(const void *p, int car, int n) car en el objeto apuntado por p, o NULL si el carácter no
está presente en los primeros n caracteres del objeto

 #include <math.h>
6.- Funciones matemáticas

Función Descripción
double sin (double n) Devuelve el seno del ángulo n (expresado en radianes).
double cos (double n) Devuelve el coseno del ángulo n (expresado en radianes)
double tan (double n) Devuelve la tangente del ángulo n (expresado en radianes)
double exp (double n) Devuelve la exponencial de n (en)
double log (double n) Devuelve el logaritmo neperiano de n (ln(n)) [si x>0]
double log10 (double n) Devuelve el logaritmo en base 10 de n [si x>0]
double sqrt (double n) Devuelve la raíz cuadrada de n [si x≥0]
double pow (double x, double y) Devuelve xy
double fabs (double n) Devuelve el valor absoluto de n (double)

#include <math.h>
#include <stdio.h>
main()
{
double var=-1.0;

do {
printf("El seno de %lf es %lf, el coseno %lf y la tangente
%lf\n", var, sin(var), cos(var), tan(var));
if (var>=0.0)
printf("y su raíz cuadrada es %lf\n", sqrt(var));
var+=0.1;
} while (var<1.1);
}

Librerías estándares de C
 #include <time.h>
7.- Funciones para la gestión de la fecha y la hora

Programación en C. Teoría 46 Dpto. ATC (UPV/EHU)


Estas funciones utilizan los dos tipos de datos siguientes:
time_t: valor aritmético para representar el tiempo
struct tm
{
int tm_sec: /* segundos, a partir del minuto 0-59 */
int tm_min; /* minutos, a partir de la hora 0-59 */
int tm_hour; /* hora desde medianoche 0-23 */
int tm_mday; /* día del mes 1-31 */
int tm_mon; /* mes desde enero 0-11 */
int tm_year; /* año desde 1990 */
int tm_wday; /* día de la semana, desde el domingo 0-6 */
int tm_yday; /* día del año, desde enero 0-365 */
int tm_isdst;
};
Función Descripción
time_t time (time_t *tp) Devuelve el tiempo actual, como valor entero, o –1 si no está
disponible. Si el parámetro tp no es NULL, asigna también el
resultado al objeto apuntado por tp
double difftime Devuelve la diferencia en segundos entre los tiempos t2 y t1
(time_t t1, time_t t2)
char * asctime Convierte el tiempo almacenado en la estructura tp en un string
(const struct tm *tp) de la forma DDD MMM dd hh:mm:ss AAAA\n\0
DDD día de la semana (alfabético)
MMM mes (alfabético)
dd día de la semana (numérico)
hh:mm:ss horas:minutos:segundos (numéricos)
AAAA año (numérico)
Por ejemplo: Sun Jan 3 15:14:13 1988\n\0
struct tm * localtime Convierte el tiempo almacenado en el objeto tp a una
(const time_t *tp) estructura tm. Devuelve un puntero a esta estructura
char * ctime Es equivalente a:
(const time_t *tp) asctime(localtime(tp))

#include <time.h>
#include <stdio.h>
main()
{
time_t ltime;
time (&ltime);
printf("Fecha de comienzo: %s\n", ctime(&ltime));
llamar_funcion();
time (&ltime);
printf("Fecha de fin: %s\n", ctime(&ltime));
}
Librerías estándares de C
También existe una función interesante para contar tiempos de ejecución: gettimeofday. Esta
función está declarada en <sys/time.h> y se basa en la estructura:

Programación en C. Teoría 47 Dpto. ATC (UPV/EHU)


struct timeval {
long tv_sec; /* segundos */
long tv_usec; /* microsegundos */
};

int gettimeofday(struct timeval *tv, struct timezone *tz);

Esta función devuelve en la estructura tv un valor numérico que representa el tiempo actual. El
segundo parámetro está obsoleto y normalmente se le llama con NULL o 0. Como resultado,
devuelve –1 en caso de error y 0 si todo ha ido correctamente.

#include <sys/time.h>
#include <stdio.h>

main()
{
struct timeval tini,tfin;
double teje;
gettimeofday(&tini,0);
llamar_funcion();
gettimeofday(&tfin,0);
teje=(tfin.tv_sec-tini.tv_sec)+(tfin.tv_usec-tini.tv_usec)/1e6;
printf("Tiempo de ejecución: %f segundos\n", teje);
}

Programación en C. Teoría 48 Dpto. ATC (UPV/EHU)


Desarrollo de programas
1.- Compilación separada
Variables y funciones extern
Estructura de ficheros: cabeceras y declaraciones (.h) + código (.c)
include de ficheros: #include <fichero.h> vs #include “fichero.h”

pruebalog.c logica.h

#include <stdio.h> .....


#include “logica.h” typedef int bool;
.....
main () extern bool logica(bool x1, bool y1);
{ .....
bool a,b,c;
.....
c=logica(a,b);
printf (“c: %d\n”,c);
.....
}
logica.c

.....
typedef int bool;
cc –c pruebalog.c .....
bool logica (bool x, bool y)
{
return (x|y);
}

pruebalog.o
main
.... cc –c logica.c
logica??

logica.o

logica

cc –o pruebalog.exe pruebalog.o logica.o

EJECUTABLE: pruebalog.exe

Programación en C. Teoría 49 Dpto. ATC (UPV/EHU)


Desarrollo de programas
2a.- Ejemplo de compilación separada: ordenar.c
#include <stdio.h>
#include <stdlib.h>
#define TOPE 20
long numeros[TOPE];
int num;
void leer_num ()
{
long valor;
num=0;
while (num<TOPE) {
printf("Introduce un numero:\n");
scanf("%ld",&valor);
if (feof(stdin)) break;
numeros[num++]=valor;
}
}
int el_primero(long *vector,int nelem,int modo)
{
int i, ind_primero=0;
for (i=1; i<nelem; i++)
if(modo==0) {if(vector[i]<vector[ind_primero]) ind_primero=i;}
else if(vector[i]>vector[ind_primero]) ind_primero=i;
return(ind_primero);
}
void ordenar_num(int modo)
{
int i, ind; long tmp;
for (i=0; i<num-1; i++) {
ind=el_primero(&(numeros[i]),num-i,modo);
tmp=numeros[i]; numeros[i]=numeros[i+ind]; numeros[i+ind]=tmp;}
}
main(int argc, char *argv[])
{
int i;
if (argc!=2) {
printf ("ERROR en parametros. PROGRAMA: %s 0/1\n",argv[0]);
exit(-1); }
leer_num(); ordenar_num(atoi(argv[1]));
printf("\nVector ordenado: ");
for (i=0;i<num;i++) printf("%ld ",numeros[i]);
printf("\n");
}

$gcc –o ordenar ordenar.c

Programación en C. Teoría 50 Dpto. ATC (UPV/EHU)


Desarrollo de programas
2b.- Ejemplo de compilación separada
//FICHERO: leern.h //FICHERO: ordenarn.h

#define TOPE 20 extern void ordenar_num(int m);


extern long numeros[TOPE];
extern int num;
extern void leer_num();

#include <stdio.h> //FICHERO: leern.c

#define TOPE 20
long numeros[TOPE];
int num;

void leer_num ()
{
long valor;
num=0;
while (num<TOPE) {
printf("Introduce un numero:\n");
scanf("%ld",&valor);
if (feof(stdin)) break;
numeros[num++]=valor;
}
}

#include "leern.h" //FICHERO: ordenarn.c


int el_primero(long *vector,int nelem,int modo)
{
int i, ind_primero=0;
for (i=1; i<nelem; i++)
if(modo==0) {if(vector[i]<vector[ind_primero]) ind_primero=i;}
else if(vector[i]>vector[ind_primero]) ind_primero=i;
return(ind_primero);
}
void ordenar_num(int modo)
{
int i, ind;
long tmp;
for (i=0; i<num-1; i++) {
ind=el_primero(&(numeros[i]),num-i,modo);
tmp=numeros[i];
numeros[i]=numeros[i+ind];
numeros[i+ind]=tmp;
}
}

Desarrollo de programas

Programación en C. Teoría 51 Dpto. ATC (UPV/EHU)


2b.- Ejemplo de compilación separada (continuación)

#include <stdio.h> //FICHERO: ordenar.c


#include <stdlib.h>

#include "leern.h"
#include "ordenarn.h"

main(int argc, char *argv[])


{
int i;
if (argc!=2)
{
printf ("ERROR en parametros. PROGRAMA: %s 0/1\n",argv[0]);
exit(-1);
}
leer_num();
ordenar_num(atoi(argv[1]));
printf("\nVector ordenado: ");
for (i=0;i<num;i++) printf("%ld ",numeros[i]);
printf("\n");
}

$gcc –c leern.c
$gcc –c ordenarn.c
$gcc –c ordenar.c
$gcc –o ordenar ordenar.o leern.o ordenarn.o

Programación en C. Teoría 52 Dpto. ATC (UPV/EHU)


Desarrollo de programas
3.- Directivas al compilador

#undef PI
#define PI 3.14159
#define area(r) (PI*(r)*(r))
#define toupper(c) ((c)>='a'&&(c)<='z'? (c)&0x5F:(c))
#include <stdio.h>
#include "pila.h"

# if, # else, # elif, # endif /* compilar -D_____ */


(1) # define TRAZA 1
# if TRAZA
printf ("El valor de la variable x es %d\n",x);
# endif
(2) # define CASTELLANO 1
# define EUSKERA 2
# define IDIOMA CASTELLANO
# if IDIOMA == CASTELLANO
printf ("Buenos días\n");
# elif IDIOMA == EUSKERA
printf ("Egunon\n");
# else
printf ("Idioma desconocido\n");
# endif

# ifdef, # ifndef /* compilar -D_____ */


# define TRAZA
# ifdef TRAZA
printf ("El valor de la variable x es %d\n",x);
# endif

#ifdef IBM
int reg_dat_inp = 0x378;
#else
int reg_dat_inp = 0x3B8;
#endif

$gcc –DIBM ... #IBM


$gcc ... #resto

Programación en C. Teoría 53 Dpto. ATC (UPV/EHU)


Resumen: tipos, constantes y variables
int enteros
decimal ddd 94 %d
hexadecimal 0xdd 0x33 %x
octal 0dd 022 %o
long int dL l6L %ld
unsigned int ddU 987U %u
short int dd 10 %d
float coma flotante
dd.ddE +-dd 3.4E -28 %f
double coma flotante
char caracter 'c', '\0' , '\n' %c

Arrays:
tipo nombre [n] [m] ..... [p] (0..n-1)
String:
char nombre [n] "ccccc"+'\0' %s
Structs:
struct {def. variables} nombre_var;
struct tipo_struct {def. variables};
struct tipo_struct nombre_var;
Unions:
union tipo_union {def. variables} nombre_var;
Enumerados:
enum tipo_enum {elem1, elem2, ...., elemn} nombre_var;
Bits:
unsigned nombre:n;

Punteros:
tipo *nombre;

Ficheros:
FILE *descriptor_fichero;

Programación en C. Teoría 54 Dpto. ATC (UPV/EHU)


Resumen: sentencias

asignación:
variable = expresión;
llamada a función:
nombre_funcion (par1,par2,...,parn);
if:
if (condición) sentencia; else sentencia; /* cond: 0-FALSE
{ } { } !=0 TRUE */
switch:
switch (expresión)
{
case cons1: sentencias;
break;
case cons2: sentencias;
break;
..............................
default: sentencias;
}
while:
do sentencia while (condicion);
{ }
while (condicion) sentencia;
{ }
for:
for (inicialización; condición; cada_iteración) sentencia;
{ }
ruptura de secuencia:
exit(); /* finaliza la ejecución del programa */
return(expresion); /* devuelve el valor de la expresión al programa llamador */
continue; /* nos envía al siguiente paso de la estructura repetitiva */
break; /* nos envía fuera del switch o de la estructura repetitiva */

Programación en C. Teoría 55 Dpto. ATC (UPV/EHU)


Resumen: operadores
Aritméticos:
+ suma
- resta
* multiplicación
/ división
% módulo
-- decrementar (pre y post)
++ incrementar (pre y post)
+= v+=(expresión) <=> v=v+(expresión)
-=
*=
/=
& and aritmético ^ xor aritmético
| or aritmético ~ complemento a 1
>> shift derecha
<< shift izquierda
Relacionales:
== igualdad
!= desigualdad
> mayor estricto
< menor estricto
>= mayor o igual
<= menor o igual
Lógicos:
&& and lógico
|| or lógico
! no lógico
Otros:
. acceso a elementos de un struct por valor
-> acceso a elementos de un struct por referencia
* contenido de lo apuntado por una dirección
& dirección de
, inicializar variables en un for
? sustituir sentencias if/else con una sola expresión

Programación en C. Teoría 56 Dpto. ATC (UPV/EHU)


Resumen: operadores (por orden de evaluación)

Primarios: () [] . -> (izda-dcha)


Unarios: + - ++ -- (dcha-izda)
* &
! ~
sizeof (cast)
Aritmeticos1: * / % (izda-dcha)
Aritmeticos2: + - (izda-dcha)
Desplazamientos: << >> (izda-dcha)
Comparación1: < > <= >= (izda-dcha)
Comparación2: == != (izda-dcha)
Lógicos1: & (izda-dcha)
Lógicos2: ^
Lógicos3: |
Comp_cond1: && (izda-dcha)
Comp_cond2: ||
Expres_cond: ? : (dcha-izda)
Asignaciones: = += -= *= (dcha-izda)
/= %= >>= <<=
&= ^= |=
Separador: , (izda-dcha)
Uso de paréntesis para cambiar este orden de evaluación.

x = y /3 - 34 * temp & 127; x = (y/3) -((34*temp)&127);


int *x[] x es
1 [ ]: un array de
2 *: punteros a
3 enteros
char *x()[] x es
1 (): una función que devuelve
2 []: un array de
3 *: punteros a
4 caracteres

Programación en C. Teoría 57 Dpto. ATC (UPV/EHU)


Resumen: conversión de tipos
Se convierten todos los operandos hacia el tipo del mayor operando
char ch; int i;
float f; double d;
result =(ch / i) + (f * d) - (f + i);
int double float
double
double

Operador cast: (tipo) expresión


(a) float x;
int y=4;
x = y/3; /* x == 1*/
x = (float) y / 3.0; /* x == 1.333 */
(b) float x=1.25;
float z;
z = (float) exp((double) x);

Resumen: directivas al compilador


# include <stdio.h>
# include "var.h"
# define NOMBRE valor
# define toupper(c) ((c)>='a' && (c)<='z' ? (c)&0x5F : (c))
# define MIN(a,b) ((a) < (b) ? (a) : (b))
# undef PI
# define PI 2.22

# if, # else, # elif, # endif /* compilar D_____ */


# define TRAZA 1
# if TRAZA
printf ("El valor de la variable x es %d\n",x);
# endif

# ifdef, # ifndef /* compilar D_____ */


# define TRAZA
# ifdef TRAZA
printf ("El valor de la variable x es %d\n",x);
# endif

Programación en C. Teoría 58 Dpto. ATC (UPV/EHU)

You might also like