Você está na página 1de 68

1.

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.

Surgió a partir de dos lenguajes de programación de sistemas, BCPL y B.

En 1978 Kernighan y Ritchie publican su descripción en el libro "The C Programming


Language", versión que es llamada hoy en día 'K&R C'.

A mediados de los ochenta ya había en el mercado numerosos compiladores C, y


muchas aplicaciones habían sido reescritas a él para aprovechar sus ventajas.

Durante este periodo de tiempo numerosos fabricantes introducen mejoras en el


lenguaje, las cuales son recogidas por un comité de estandarización ANSI y establecen
las especificaciones de lo que se conoce hoy en día como 'ANSI C'.

1.2. Características del lenguaje


El C se encuentra en la jerarquía de lenguajes en un nivel intermedio entre Pascal y el
Ensamblador. Pretende ser un lenguaje de alto nivel con la versatilidad del bajo nivel.

Se diseñó junto con el sistema operativo UNIX y está muy orientado a trabajar en su
entorno.

En su desarrollo se siguieron una serie de líneas generales tales como:

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.

Una de las características más apreciadas de C es su gran portabilidad, gracias a que


deja en manos de librerías las funciones dependientes de la máquina, ¡y todo ello sin
restringir el acceso a dicha máquina!

Estas y otras características lo hacen adecuado para la programación en areas tales


como:

• 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:

• Lo poco estricto que es el lenguaje con la comprobación


de los tipos de datos, dejando esta tarea muchas veces en manos
del programador.
• El no verificar automáticamente los límites de los
vectores.
• La repetición que hace de símbolos en operadores
diferentes (=,*,-). (Sobrecarga de operadores).
• El no poder anidar funciones, con lo que se dificulta la
estructuración y la abstracción de datos.
• La incertidumbre existente en el orden de evaluación de
las listas de expresiones y parámetros.
• La facilidad con que los programas pueden derivar hacia
ser crípticos.

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

2. Identificadores, palabras reservadas y caracteres


especiales
Un identificador puede estar compuesto de cualquier combinación de letras (minúsculas
y mayúsculas), dígitos y el símbolo subrayado '_'. La única restricción es que el primer
carácter debe ser una letra o un subrayado.
Identificadores válidos Identificadores no válidos
x 4num (primer carácter
y2 no es letra)
suma_1 “x” (carácter ilegal “)
_t orden-no (carácter ilegal -)
TABLA ind lis (espacio ilegal)
Figura 2 Ejemplos de identificadores legales e ilegales

No se limita la longitud de los identificadores. Pero algunas implementaciones sólo


reconocen los 8 primeros y otras (ANSI) los 31 primeros caracteres.

Se diferencia entre mayúsculas y minúsculas.

Existe un conjunto de caracteres que tienen un significado especial en el lenguaje C. Se


muestran en la figura3.
! * + \ " <
# ( = | { >
% ) ~ ; } /
^ _ [ : , ?
& - ] ' . (blanco)
Figura 3 Caracteres especiales.

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.

auto extern sizeof


break float static
case for struct
char goto switch
const if typedef
continue int union
default long unsigned
do register void
double return volatile
else short while
enum signed
Figura 4 Palabras reservadas de C

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:

char short int int


long int unsigned char unsigned short int
unsigned int unsigned long int double
float long float void
Figura 5 Tipos de datos fundamentales

char Representa un carácter en código ASCII, también se puede


interpretar como
un entero.

short int Indica un entero de tamaño corto.

int Entero igual que integer en Pascal.

long int Entero largo.

unsigned short int Como short int pero sin signo.

unsigned int Como int pero sin signo.

unsigned long int Como long int pero sin signo.

float Flotante corto. Análogo al single de Pascal.

double Flotante largo. Análogo al double de Pascal.

void No indica ningún tipo. Es el tipo de las funciones que no devuelven


nada.

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)

Donde sizeof es un operador que está incorporado en C y devuelve el número de bytes


que tiene un objeto.

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, ...;

Nombre es el nombre de la estructura y los identificadores corresponden a variables del


tipo de la estructura. Tanto el nombre como las variables pueden no existir. Los
miembros son las componentes de la estructura. La forma de declarar variables del tipo
definido en la estructura es:

[cualificador] struct nombre 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:

modificador union nombre {


tipo miembro1;
tipo miembro2;
...
} identificador1, identificador2, ...;

La forma de declarar variables del tipo unión es:

cualificador union nombre variable1, variable2, ...;

union palabra { Se declaran 4 variables


unsigned char l[2]; a,b,c y d
unsigned int x; A cada variable se puede
} a,b,c,d; acceder como entero (x) o
como 2 bytes (l[2]).

a.x = 65535U; a.x es un entero


a.l[0] = 0; a.l[0] es un byte
a.l[1] = 255; a.l[1] es un byte
¿Cuánto vale a.x en este punto?
Figura 7 Ejemplo de unión

typedef Permite definir un nuevo tipo de datos en función de los ya existentes. Es


análogo a las declaraciones type de Pascal. La forma general de definir un nuevo tipo
es:

typedef tipo nuevo-tipo;

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 */

typedef unsigned char byte; /* Tipo byte de Pascal */


typedef unsigned int word; /* Tipo word de Pascal */
Figura 8 Ejemplos de typedef

enum Es análogo a un tipo enumerado de Pascal. Sirve para especificar los miembros
de un determinado tipo.

enum nombre { miembro0 = valor0 , miembro1 = valor1 , ... }


variable1, variable2, ...

Las expresiones = valorX son opcionales, encargándose el compilador de asignar un


valor constante a cada miembro que no la posea.

enum colores {negro =-1,azul, cian, magenta, rojo = 2,


blanco} fondo, borde;
enum colores primer_plano;
fondo = cian;
Figura 9 Ejemplo de enum

5. Declaración de variables
La forma general de declarar variables en C es la siguiente:

cualificador tipo identificador = valor, identificador = valor, ... ;

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.

int a,b,c; Tres variables enteras.


float raiz1, raiz2; Dos variables de tipo real.
char caracter, texto[80]; Un caracter y una cadena de
80.
short int a; Entero corto.
long int b; Entero largo.
unsigned short int d; Entero corto sin signo.
unsigned char a; Caracter sin signo.
signed char b; Caracter con signo.
char texto[3] = "abc"; Declaración e inicialización
char a = '\n'; Inicialización con Return.
char texto[] = "abc"; Sin especificar tamaño.
extern unsigned short int Variable externa.
Figura 10 Ejemplos de declaración de variables.

6. Arrays
En C los arrays son de tamaño fijo, es decir, su tamaño se especifica en tiempo de
compilación.

No se comprueba la longitud del array a la hora de acceder. Es responsabilidad del


programador controlar los accesos fuera de rango.

Si se pretende escribir en la posición 20 de un array y este ha sido declarado de 10


componentes, no se generará ningún error (ni siquiera en tiempo de ejecución) y se
escribirá en memoria en la dirección donde debería ir el elemento 20 si lo hubiera, por
lo que se puede variar el contenido de otra variable, o incluso de parte del programa, o
peor aún, se puede destruir parte del sistema operativo.
La forma de declarar arrays en C es la siguiente:

cualificador tipo variable[expresión][expresión]... ={valor, ...};

La expresión y los valores deben ser constantes. Si se declara la parte de valores se


puede eliminar la expresión. En este caso el tamaño del vector es el mismo que el
número de valores que se especifican. No se admite el cualificador register.
La forma de hacer referencia a un elemento del vector es:

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).

7.1. Constantes enteras


Se pueden escribir en decimal (número que no empieza por 0), octal (el primer dígito es
0) y hexa (comienza con 0x ó 0X). Además pueden ser con signo o sin signo. Si es sin
signo se les añade el sufijo U. El tamaño de las constantes puede ser normal o largo, en
este caso se añade el sufijo L.

tamaño normal tamaño largo


con signo L
sin signo U UL (en este orden)

7.2. Constantes en coma flotante


Debe aparecer el punto decimal o la letra E (o e) de exponente. Si se desea especificar
que se represente la constante en simple precisión se añade el sufijo F y en larga
precisión el sufijo L o sin ninguno.

7.3. Constantes de caracteres


Es un sólo carácter o una secuencia de escape encerrado con comillas simples.
Las secuencias de escape son las que se presentan en la Figura 11:
sonido (campana) '\a'
backspace '\b'
tab horizontal '\t'
tab vertical '\v'
nueva línea '\n'
form feed '\f'
retorno de carro '\r'
comillas(") '\"'
comilla simple(') '\''
signo interrogación '\?'
backslash (\) '\\'
nulo '\0'
Figura 11 Secuencias de escape

Mediante secuencias de escape se puede expresar cualquier carácter ASCII indicando su


código en octal (\ooo) o en hexa (\xhh). Donde los símbolos 'o' representan dígitos
octales y las 'h' dígitos hexadecimales.

7.4. Constantes de cadenas de caracteres


Constan de cualquier número de caracteres o secuencias de escape consecutivos entre
comillas dobles. También se admite ausencia de caracteres (""). El carácter nulo no
puede aparecer en medio de una constante de cadena de caracteres puesto que se usa
para indicar fin de cadena. El carácter de fin de cadena '\0' se coloca de forma
automática en las cadenas literales; así en la cadena "abc" hay 4 caracteres: a, b, c y '\0'.

7.5. Constantes enumeradas


Son las definidas de tipo enum

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.

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


nuestro espacio de trabajo.

8.1. Declaración de punteros


La forma de declarar un puntero es la siguiente:

cualificador tipo *nombre, *nombre;

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:

a) Inicializarlo con el valor NULL (definido en un fichero header). De este modo


estamos indicando que el puntero no apunta a ninguna memoria concreta.
b) Inicializarlo haciendo que tome como valor la dirección de una variable.
int *p, a;
p = &a;
A partir de estas sentencias, *p y a son alias.
c) Asignarle memoria dinámica a través de una función de asignación de memoria. Las
funciones más habituales son calloc y malloc, definidas en el fichero alloc.h o bien en
stdlib.h
void *malloc(size_t size)
void *calloc(size_t n_items, size)

Una inicialización de un puntero a un tipo T tendría la forma:

p = (T*)malloc(sizeof(T));

8.2. Punteros a una estructura


Existe una pequeña variación a la hora de acceder a una estructura mediante un puntero,
por ejemplo, (*p).miembro se puede escribir como p->miembro.

8.3. Paso de punteros a una función


El lenguaje C sólo admite paso de parámetros por valor, pero tiene una forma de
simular un paso por referencia (variable), pasando un puntero que es la dirección donde
están los datos (p. ej. &v). En realidad se pasa un valor que es una dirección de una
variable.

void func(int *pa,int b) {


*pa = 1;
b = 2;
return ;
}

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

8.4. Punteros y arrays unidimensionales


El identificador de un array se considera un puntero al primer elemento del array.
Cualquier forma de acceder como un array puede ser sustituida por su forma
equivalente como puntero.

int x[100]; Declaración de un array de 100 enteros


x[0] *x Primer elemento del array
x[2] *(x + 2) Tercer elemento del array
x x Dirección del array
&x[3] (x + 3) Dirección del tercer elemento del array

char a[] ="Pulsa Return";

a[0] *a Carácter "P"


a[i] *(a + i) Carácter i-ésimo
&a[0] a Dirección de la cadena
Figura 14 Ejemplos de punteros y arrays unidimensionales

Las strings (cadenas de caracteres) se consideran arrays de caracteres a todos los


efectos.

8.5. Operaciones con punteros


A los punteros se les puede añadir o restar una cierta cantidad entera. Admiten
comparaciones e incrementos y decrementos. Cuando un puntero es incrementado en
uno pasa a apuntar al siguiente elemento del array a que apuntaba, no al siguiente byte,
es decir, se incrementa en el número de bytes que ocupa el tipo al que apunta. También
se permite restar dos punteros para calcular la distancia entre ellos.

int *px, *py;


px < py
px <= py
px > py
px >= py
px == py
px != py
px == NULL
a = *(px++) Postincremento del puntero
a = *(++px) Preincremento del puntero
px - py “Distancia” entre los punteros px y
py
Figura 15 Operaciones con punteros

8.6. Punteros y arrays multidimensionales


Una matriz bidimensional es implementada en C como un vector cuyos elementos son
vectores. Es decir, la matriz se implementa en forma de vector, sin embargo, cuando
accedemos a ella sigue teniendo la forma de matriz.
La forma de declarar un array multidimensional es:

tipo nombre[expresion1][expresion2]...;

La forma de acceder a un elemento de la matriz es:

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.

8.7. Arrays de punteros


Al igual que de cualquier otro tipo de dato se permite declarar un array de punteros. La
forma de hacerlo es:

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.1. Operaciones aritméticas


+ Suma
- Resta
* Multiplicación
/ División
++ Incremento
-- Decremento
% Módulo

9.2. Operaciones lógicas


|| OR lógico
&& AND lógico
! NOT lógico
^ XOR lógico

9.3. Operaciones de bits


| OR
& AND
~ NOT
>> Desplazamiento a la derecha
<< Desplazamiento a la izquierda
9.4. Comparaciones
< Mayor que
> Menor que
<= Menor o igual que
>= Mayor o igual que
== Igual que
!= Distinto que

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

9.6. Operadores especiales


? : Operador If de expresiones
, Separador de expresiones
* Valor apuntado por un puntero (indirección)
& Dirección de una variable
(type) Typecasting, donde type indica el tipo de datos al que se
convierte el resultado de la expresión.
sizeof type Devuelve el número de bytes necesarios para representar
un determinado tipo de datos.
. Cualificador. Separador de campos
-> (p*).a es equivalente a: p->a

9.7. Precedencia de los operadores


() [] -> .
! ~ ++ -- - (type) * & sizeof (todos son unarios)
* / %
+ -
<< >>
< <= > >=
== !=
&
^
|
&&
||
?:
= += -= *= /= %= ^= &= |=
,

9.8. Incremento ++ y decremento --


Existen dos formas de incrementar y decrementar variables: postincremento y
postdecremento, y preincremento y predecremento. En los primeros se calcula la
expresión con el valor de la variable y luego se incrementa o decrementa dicha variable,
con los segundos se incrementa o decrementa y luego se calcula la expresión.

9.9. Detalle sobre los operadores de asignación


Las asignaciones son operadores, es decir devuelven un valor. El valor que devuelven es
el correspondiente al operando de la parte derecha.

int a, b, c;
a = b = c = 0;
a += b = c;
Figura 16 Ejemplos de asignaciones

Esta propiedad permite que se realicen expresiones como el condicional:

if ((x = f(y) == N) ...

Preferiremos habitualmente el código equivalente:

x = f(y);
if (x == N) ...

9.10. Conversión de tipos


Existe un tipo de conversión automática cuando tratamos con expresiones aritméticas (x
op y) que cumple las siguientes reglas:
1. Todos los char o short se convierten a int.
Todos los unsigned char o unsigned short se convierten a unsigned.
2. Si después del paso anterior la expresión es de tipo mixto,
el operando de tipo menor se convierte al de tipo mayor según la jerarquía:
int < unsigned < long < unsigned long < float < double
Considérense las declaraciones:
char c; float f; int i;
short s; unsigned u;

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

También podemos realizar conversiones de tipo explícitas llamadas type casts


(invitación de tipos), indicando el tipo anfitrión entre paréntesis.

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).

10.1 Sentencia while


while (expresión) sentencia

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.

/* Cálculo de la media de un vector */


int v[100], i = 0, media, suma = 0;
while (i < 100)
suma += v[i++];
media = suma / 100;
Figura 18 Ejemplo de sentencia while

10.2 Sentencia for


for (expresión1; expresión2; expresión3) sentencia

Es la sentencia de control más potente y la más usada. Consta de tres expresiones: la


primera es la inicialización del bucle, la segunda indica la condición en la que se debe
continuar el bucle y la tercera es la que se encarga de incrementar los índices del bucle.
Expresión1 se ejecuta una sola vez al principio del bucle. La sentencia se ejecuta
mientras la expresión2 sea verdadera (no 0). Esta expresión es evaluada antes que la
sentencia por lo que es posible que el bucle no se ejecute ni siquiera una vez. La
expresión3 se ejecuta después de la sentencia. Las expresiones 1 y 3 pueden ser
compuestas, expresiones simples separadas por comas. La instrucción for equivale
directamente a lo siguiente.

expresion1;
while (expresion2) {
sentencia;
expresion3;
}

/* Cálculo de la media de un vector */


int v[100], i, media, suma = 0;
for (i = 0; i < 100; i++)
suma += v[i];
media = suma / 100;
Figura 19 Ejemplo de bucle for

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;

/* Nótese que en C se escribe ";" antes del else */


Figura 20 Ejemplo de sentencia if-else

10.4 Sentencia do-while


do sentencia while (expresión);

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.

/* Cálculo de la media de un vector */


int v[100], i, media, suma = 0;
i = 0;
do
suma += v[i++];
while (i < 100);
media = suma / 100;
Figura 21 do-while

10.5 Sentencia switch


switch (expresión) {
case expresión1: sentencia; sentencia; ...
case expresión2: sentencia; sentencia; ...
case expresión3: sentencia; sentencia; ...
default: sentencia; sentencia; ...
}

Es análoga a la sentencia case de Pascal. La expresión se evalúa y si su valor coincide


con el valor de alguna expresión indicada en los case se ejecutan todas las acciones
asociadas que le siguen. Las expresiones deben ser de tipo entero o carácter. Si el valor
de expresión no se encuentra en la lista case se ejecuta/n la/s sentencia/s
correspondiente/s a la opción default, si ésta no existe se continúa con la sentencia
situada a continuación de switch. Una vez se elija una opción se ejecutan las sentencias
asociadas y se continúan ejecutando todas las sentencia a partir de ésta (incluso las
correspondientes a otras opciones) hasta que aparezca una sentencia break.

10.6 Sentencia break


break

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

10.7 Sentencia continue


continue

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

Es análoga a su equivalente Pascal. Le debe seguir una etiqueta a la que transferir


control. Sólo se permiten saltos dentro del cuerpo de una función. La forma de definir
las etiquetas es la misma que en Pascal, es decir, un identificador seguido de dos puntos.
No es necesario declarar las etiquetas previamente.

11. Funciones
El lenguaje C sólo permite funciones, no hay procedimientos. La forma de declarar las
funciones es la siguiente:

tipo nombre(tipo parámetro_1, ... tipo parámetro_N) sentencia

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:

tipo nombre(tipo parámetro_1, ... tipo parámetro_N);

O sea, la cabecera de la función acabada en punto y coma. Es análoga una declaración.


Como se comentó anteriormente sólo existe paso por valor.
Para terminar la ejecución de una función se usa la sentencia return. Su sintaxis es:

return [expresión];

Donde la expresión es el valor que retorna la función. Debe ser del mismo tipo que el de
la función.

void funcion1(int a); /* Prototipo de la función */


void funcion2(void); /* Prototipo de la función */

/* trozo de programa */
void funcion1(int a) { /* Función 1 */
/* Cuerpo de la función */
funcion2();
}

void funcion2(void) { /* Función 2 */


/* Cuerpo de la función */
funcion1(2);
}
Figura 23 Funciones

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.

#include <stdio.h> Incluye la cabecera para usar las


librerias
de entrada/salida desde el
directorio estándar

#include "stdio.h" Igual al anterior pero las busca


en el directorio actual

#include "a:\librería\mia.h" Incluye el fichero mia.h


desde la unidad a:
Figura 24 Ejemplo de inclusión de librerías

12.1. Operaciones sobre ficheros


Existen dos niveles para trabajar con ficheros. Un nivel bajo compatible con UNIX en
donde las lecturas y escrituras en ficheros se realizan sobre cadenas de bytes y el
programador debe implementar los buffers. Y un nivel alto que permite lectura-escritura
de ficheros usando datos, estructuras y buffering. Las funciones del nivel bajo se
encuentran fundamentalmente en el fichero io.h y las de alto nivel en el fichero stdio.h.
Funciones para abrir, leer, escribir y cerrar ficheros en alto nivel (modo texto) son
fopen, fscanf, fprintf, fclose mientras que sus análogas en bajo nivel (modo binario)
son open, read, write y close.

12.2. Manejo de cadenas


Existe una librería que contiene todas las funciones para manejar cadenas cuyas
declaraciones estan en string.h. Todas estas funciones consideran a una string como una
secuencia de caracteres acabada en nulo ('\0').

12.3. Algunas librerías y funciones importantes en


ANSI C
• alloc.h Contiene las funciones para obtener y liberar
memoria.
o void *calloc(size_t n_elem, size_t
ele_size);

Reserva espacio contiguo para n_elem elementos de


tamaño cada uno ele_size bytes.
Devuelve un puntero al bloque o NULL si no hay
suficiente espacio.

o void *malloc(size_t size);

Reserva size bytes de memoria. Devuelve un apuntador al


comienzo de dicha memoria
NULL.

o void free(void *block);

Libera bloques reservados previamente con calloc o


malloc.

• conio.h Es la librería que contiene las funciones de


entrada salida desde la consola.

• ctype.h Contiene funciones que indican características de


los caracteres, por ejemplo, si está en mayúscula o en minúscula,
si es un dígito hexa valido, etc.
o int isalnum(char c); Verdad si c es una letra
o un dígito.
o int isalpha(char c); Verdad si c es una
letra.
o int isdigit(char c); Verdad si c es un
digito.
o int islower(char c); Verdad si c está en
minúscula.
o int isupper(char c); Verdad si c está en
mayúscula.
o int isspace(char c); Verdad si c es un
espacio, tabulador, retorno de carro,

nueva linea, tabulador vertical o


salto de página.

• errno.h Declara una lista de constantes de error que


devuelven las funciones de entrada salida.

• fcntl.h Define los flags para los modos de apertura de un


fichero.

• stdlib.h Conjunto de funciones estándar.


o double atof(char *s); Convierte una cadena en
un flotante double.
o int atoi(char *s); Conviete una cadena a un int.
o long atol(char *s); Convierte una cadena a un
long.
o void exit(int status); Termina el programa
devolviendo status.
o char *ecvt(double value, int ndig, int
*dec, int *sign);

Convierte u número de flotante a cadena.

o char *itoa(int value, char *string, int


radix);

Convierte de int a cadena.

o char *ltoa(long value, char *string, int


radix);

Convierte de long a cadena.

o char *ultoa(unsigned long value, char


*string, int radix);

Convierte de unsigned long a cadena.


• math.h Conjunto de funciones matemáticas.
o int abs(int x); Valor
absoluto de un entero.
o double sin(double x); Seno.
o double cos(double x); Coseno.
o double tan(double x);
Tangente.
o double atan(double x);
Arcotangente.
o double exp(double x); Calcula
e elevado a x.
o double log(double x);
Logaritmo neperiano.
o double sqrt(double x); Raiz
cuadrada.
o double pow(double x, double y); Obtiene
la potencia x elevado a y.
• string.h Funciones de manejo de cadenas.
o int strcmp(char *s1, char *s2);

Compara s1 y s2, devolviendo <0, 0 ó >0 según sea


s1<s2, s1==s2 ó s1>s2.

o int strncmp(char *s1, char *s2, size_t


maxlen);

Igual que strcmp, pero con los maxlen primeros


caracteres.

o int stricmp(char *s1, char *s2);

Igual que strcmp pero sin diferencial mayúsculas de


minúsculas.

o int strnicmp(char *s1, char *s2, size_t


maxlen);

Mexcla de stricmp y strncmp.

o size_t strlen(char *s);

Devuelve el número de caracteres en s, sin contar /0.

o char *strchr(char *str, int c);

Busca el primer caracter c en str y retorna un puntero a


dicha c o NULL si no hay.

o char *strrchr(char *str, int c);


Busca el último caracter c en str y retorna un puntero a
dicha c o NULL si no hay.

o char *strpbrk(char *s1, char *s2);

Busca dentro de s1 el primer caracter de los de s2,


devolviendo un puntero a dicha
posición o NULL si no hay.

o char *strcat(char *dest, char *src);

Añade src al final de dest.

o char *strncat(char *dest, char *src,


size_t maxlen);

Añade a lo sumo maxlen caracteres de src a dest.

o char *strcpy(char *dest, char *src);

Copia la cadena src en dest, devolviendo dest.

o char *strlwr(char *s);

Convierte s a minúsculas.

o char *strupr(char *s);

Convierte la cadena a mayúsculas.

12.4. Funciones de entrada/salida más importantes


Los ficheros estandar definidos en todo sistema C son:
stdin (entrada estandar, asociado al teclado)
stdout (salida estandar, asociado a la pantalla)
stderr (error estandar, asociado a la pantalla)
stdaux (auxiliar estandar)
stdprn (impresora estandar)

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

• char getchar(void)
Entrada estándar de carácter. Obtiene un carácter de la entrada
estándar y este es el valor que devuelve la función.
• int printf(const char *format, ...)
Imprime por la salida estándar una secuencia de caracteres cuya
estructura está definida en la string format. Se permite dar salida
a cualquier tipo de dato predefinido. La string format tiene la
estructura de una string normal pero admite además caracteres de
conversión (%) para indicar qué tipo de dato se ha de imprimir.
La estructura de una cadena de formato es:

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

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


tipo de justificación; width a la anchura utilizada para
imprimir; .prec a la precisión a la hora de escribir números en
coma flotante. El último campo opcional afecta a la
interpretación del argumento.

%c 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

• int scanf(const char *format, ...)


Es el equivalente a printf para la entrada estándar de datos de
forma estructurada. En la cadena de formato se pueden poner
todos los caracteres de conversión (%) de la tabla anterior.
Además admite %[cadena], donde se acepta cualquier cadena
formada por elementos pertenecientes a cadena, o si la cadena
comienza con '^', los no pertenecientes.

• FILE *fopen(const char *filename,const char


*mode)
Abre un fichero en alto nivel. filename es el nombre del fichero y
mode indica el modo de apertura del fichero, en la Figura 26 se
indican los valores posibles. Retorna un puntero al descriptor del
fichero (FILE).

"r" Abrir un archivo existente solo para lectura


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

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


"w+" Abrir un archivo nuevo para lectura y escritura
"a+" Abrir un archivo nuevo para leer y añadir
Figura 26 Modos de apertura de un fichero

• int fclose(FILE *fp)


Cierra un fichero cuyo puntero al descriptor es fp.

• int fprintf(FILE *fp,const char *format, ...)


Escribe en el fichero descrito por fp datos con el formato
indicado por format.

• int fscanf(FILE *fp,const char *format, ...)


Lee del fichero descrito por fp. Tanto esta llamada como la
anterior son las equivalentes de printf y scanf que operan sobre
ficheros.

#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

13. Características avanzadas de C


13.1. Operador ?:
Es un operador ternario equivalente a if-else. Su sintaxis es:

(condición) ? expresión1 : expresión2

Antes del signo de interrogación debe aparecer una condición. Si la condición es


verdadera se evalúa expresión1 y el valor devuelto por el operador ?: será su resultado.
Si la condición es falsa se devuelve el resultado de expresión2.

if (a > b) /* Cálculo del máximo de dos variables */


c = a;
else
c = b;
c = (a > b) ? a : b; /* Equivalente con el operador ?: */
Figura 28 Operador ?:

13.2. Punteros a funciones


Existe un tipo especial de punteros que es el puntero a una función. La forma de
declararlo es:

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

14. Estructura de un programa en C


En C existe una función principal (main) que es la primera que se ejecuta. Puede tener
dos o tres parámetros. El primer elemento es el número de elementos de la línea de
comandos (contando el propio nombre del programa que se ha ejecutado), el segundo es
un puntero a un vector de punteros que a su vez apuntan a cadenas que contienen cada
uno de los elementos de la línea de comandos y el tercero es un puntero al entorno.

main(int argc, char *argv[])


/* Típica declaración de la función main() */

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


/* Cuerpo de la función main */
}
Figura 30 Función main()

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.

15.2. #define y #undef


#define declara una macro o una constante y #undef borra una macro de la tabla de
definiciones.

15.3. #if, #ifdef, #ifndef, #else y #endif


Se puede preguntar por el valor de una constante o la existencia o no de una macro. En
caso de ser cierta la condición se compila el código entre #if y #else, en caso de ser falsa
se compila el código entre #else y #endif.

#define NULL 0 /* Definición de constante */

#ifdef DEBUG
/* Código para depuración */
#else
/* Código definitivo (sin depuración) */
#endif

#undef VGA /* Quita de la tabla la definición de VGA */


Figura 31 Algunas directivas del Preprocesador

16. Convenios a la hora de escribir en C


Existen una serie de convenios que no pertenecen de por sí al lenguaje C, pero que se
usan para hacer más legibles los programas, sobre todo para programadores que no han
realizado la implementación.
Un buen programador debería codificar aprovechando toda oportunidad que asegure
que su código es claro y fácil de comprender. No debe utilizar "trucos inteligentes" a los
cuales C se presta con facilidad. Considérese a mondo de ejemplo los siguientes
fragmentos de código:

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.1. Reglas de tipo general


• Comentar, comentar, comentar. Documentar
convenientemente los programas es imprescindible en cualquier
lenguaje.
• Utilizar siempre la regla KISS: Keep It Simple, Stupid.
Claro y sencillo es siempre preferible a complejo y maravilloso.
• Evitar efectos laterales. Utilizar los operadores ++ y --
siempre en una única línea por sí mismos (no imbuídos en otras
sentencias complejas).
• Nunca colocar asignaciones dentro de los condicionales.
Nunca colocar una asignación dentro de otra sentencia.
• Considere la diferencia entre = y ==. Utilizar = en lugar de
== es un error muy común y difícil de encontrar, especialmente
entre programadores procedentes de otros lenguajes.
• Nunca haga "nada" de forma "silenciosa".

/* Nunca programe de este modo */


for (index = 0; data[index] < key; index++);

/*¿Ha notado el punto y coma al final de la línea anterior?


*/

/* Forma correcta para hacer lo mismo: */


for (index = 0; data[index] < key; index++)
; /* No hacer nada */

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++)

o Coloque siempre espacios a ambos lados de un


operador binario:
Es preferible a + b
que a+b
16.3. Reglas que atañen al diseño
• Cuando diseñe sus programas, tenga en mente la "ley del mínimo asombro", que
establece que su programa se debe comportar de modo que asombre lo menos
posible al usuario.
• Haga la interface de usuario tan simple y consistente como sea posible.
• Provea al usuario final de tanta ayuda como le sea posible.
• Identifique claramente todos los mensajes de error con la palabra "error" y trate de
dar al usuario alguna idea de cómo corregir el problema.

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.

16.5. Sentencia switch


• Coloque siempre una opción default en las sentencias switch (incluso en caso que no
haga nada.
• Todas las opciones de una sentencia switch deben finalizar con un break.

16.6. Reglas de estilo


• Los programas de un cierto tamaño se suelen dividir en varios ficheros fuente. Cada
uno de los ficheros realiza una determinada parte del trabajo, pudiéndose compilar
por separado para posteriormente enlazarlos juntos y crear el ejecutable.
• Un único bloque de código delimitado por { } no debe extenderse más de tres
pantallas. Si se da ese caso, el código debería estar dividido en funciones más
pequeñas y simples.
• Cuando el código comienza a salirse de la pantalla por la parte derecha de la misma
es el momento de dividirlo en módulos más pequeños y simples

16.7. Disposición de las llaves


Las llaves izquierdas (abiertas) se suelen añadir a otras líneas de manera que no ocupen
ellas solas una línea. Por ejemplo, se suelen colocar en la misma línea que un if, for,
while, etc., cerrarla justo antes de else y abrirla justo después, etc.
16.8. Sangrado
El sangrado que se utiliza es el normal de cualquier lenguaje de programación,
sangrando más a la derecha el contenido de los bloques (if, for, while, {, ...) con
anidamientos más profundos.

16.9. La función main()


Normalmente la función main no hace nada, es decir, en ella no se codifica la solución
del problema. Sólo se encarga de llamar a la funciones que implementan la solución del
problema.

17. Herramientas de ayuda a la programación en C


Exponemos brevemente en este epígrafe algunos programas relacionados con la
programación en C. Estos programas/utilidades son estandar y habituales en entornos de
programación UNIX, pero también en el entorno MS-DOS se pueden conseguir
versiones de los mismos. Todas las utilidades que se describen se encuentran
disponibles en el Servidor de red del C.S.I.. Las utilidades que acompañan a los
compiladores de Borland se encuentran instaladas en los directorios llamados BIN
correspondientes a la aplicación. Por ejemplo, las que acompañan al Borland C++ 2.0 se
encuentran en el directorio

X:\PROG\COMP\BC20\BIN

del servidor de red Novell. En caso de tener dificultades en la localización de alguna de


ellas, consultar al personal encargado de la administración de Sistemas del Centro.

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:

LINT f1[.C] f2[.C] ... f6[.C]

ello provoca que se ejecute el siguiente fichero de comandos:


X:\CAMINO\lint2 +v -iX:\CAMINO\ std.lnt %1 %2 %3 %4 %5 %6 >_lint.tmp
type _lint.tmp | more
@echo off
echo ---
echo PC-lint for C output placed in _LINT.TMP

donde X: es la unidad de disco correspondiente a la red y \CAMINO\ representa el


PATH correspondiente a la instalación de PC-Lint en la red: \PROG\COMP\PCLINT\.
Como se ve, los mensajes de error de PC-Lint quedan almacenados en el fichero
_lint.tmp que además es mostrado por pantalla.
La opción +v implica la activación de los mensajes informativos.
La opción -i implica que los ficheros necesarios que no se encuentren en el directorio de
trabajo se buscarán en el directorio especificado a continuación.
El fichero std.lnt contiene los nombres de otros ficheros en los que se especifica el
modo de trabajo de PC-Lint:

co-tc.lnt: Contiene ciertas opciones para ser utilizadas con los compiladores de
Turbo C, Turbo C++ y Borland C++

options.lnt: Habitualmente el usuario deberá colocar una copia de este fichero en


su propio directorio. Es un fichero en el que el usuario puede incluir su propia política
de eliminación de mensajes. Incluyendo en ese fichero líneas con el formato:

-eN

donde N es un cierto número, conseguiremos que PC-Lint no genere el mensaje número


N.

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".

Lintdemo.c Un programa de ejemplo para ejecutar pc-lint

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:

Turbo GREP Version 3.0 Copyright (c) 1991 Borland International


Syntax: GREP [-rlcnvidzuwo] searchstring file[s]
Options are one or more option characters preceeded by "-", and
optionally
followed by "+" (turn option on), or "-" (turn it off). The default is
"+".
-r+ Regular expression search -l- File names only
-c- match Count only -n- Line numbers
-v- Non-matching lines only -i- Ignore case
-d- Search subdirectories -z- Verbose
-u- Update default options -w- Word search
-o- UNIX output format Default set: [0-9A-Z_]

A regular expression is one or more occurrences of: One or more


characters
optionally enclosed in quotes. The following symbols are treated
specially:
^ start of line $ end of line
. any character \ quote next character
* match zero or more + match one or more

[aeiou0-9] match a, e, i, o, u, and 0 thru 9


[^aeiou0-9] match anything but a, e, i, o, u, and 0 thru 9
Figura 32 Opciones del Grep de Borland

Como se observa, es posible utilizar expresiones regulares para buscar la cadena de


caracteres que se desee. El entorno integrado del Borland C++ 2.0 también está
preparado para invocar Grep utilizando la opción correspondiente del menú.

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:

• Lee un fichero especial (fichero makefile) que ha de crear


el usuario. Este fichero indica a make qué ficheros objeto (con
nombre *.obj en DOS y *.o en unix) y librerías (con nombre *.lib
en DOS y *.a en unix) han de ser enlazados con el linker para
generar el fichero ejecutable, y qué ficheros fuente (*.c) y de
cabeceras (*.h) han de compilarse para generar cada uno de los
ficheros objeto.
• Compara la fecha y hora de cada fichero objeto con la de
los correspondientes ficheros fuente de los que depende: si alguna
de estas fechas es posterior a la del fichero objeto, make detecta
que el fichero fuente ha sido modificado y que debe ser
recompilado.
• Invoca al compilador de línea para recompilar el fichero
fuente que ha sido modificado.
• Una vez que los ficheros objeto han sido actualizados,
compara las fechas de éstos con las del correspondiente
ejecutable.
• Si la fecha de alguno de los ficheros objeto es posterior a
la del ejecutable, invoca al enlazador (linker) para generar de
nuevo el fichero ejecutable (*.exe en DOS).
• Como se puede observar, make se basa fuertemente en la
fecha y hora que el sistema operativo coloca a los ficheros. Si se
va a trabajar con esta utilidad, es fundamental mantener el reloj y
calendario del sistema actualizado.

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.

make_es.txt La página de manual (man) del GNU make (en español)


make_in.txt La página de manual (man) del make de SunOS (en inglés)
adios.mak Un fichero makefile (DOS) para construir el programa adios.exe a partir de
adios.c
words.mak Un fichero makefile (DOS) para construir el ejecutable words.exe

17.4. Otras utilidades


El programa PR.EXE es lo que se conoce por un Pretty Printer. Permite obtener listados
por impresora de los programas, realizando ciertas funciones sobre los ficheros que
procesa. Ejecutarlo sin parámetros para ver las opciones que permite.
FILT.EXE es un programa que realiza ciertas funciones de filtrado sobre un fichero de
texto: elimina espacios en blanco sobrantes, cambia tabuladores por espacios y
viceversa, etc. Ejecutarlo sin parámetros para ver sus opciones.
La utilidad TOUCH modifica la fecha y hora de los ficheros que se le indiquen,
colocándoles la fecha y hora actual.

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));

printf("\n\nTama¤os de los tipos reales: float: %d double: %d long


double: %d\n", sizeof(float), sizeof(double), sizeof(long double));
printf("Tama¤o C1: %d\n", sizeof(C1));
printf("Tama¤o C2: %d\n", sizeof(C2));
printf("Tama¤o del vector: %d\n", sizeof(vector));

/* El 4§ byte es para el caracter de fin de cadena, '\0' */


printf("Tama¤o de la cadena1: %d\n", sizeof(cadena1));
printf("Tama¤o de la cadena2: %d\n", sizeof(cadena2));

/* Todos los punteros ocupan el mismo tama¤o en memoria 2 bytes si son


near */
printf("Tama¤o de puntero a entero ip: %d\n", sizeof(ip));
printf("Tama¤o de puntero a char cp: %d\n", sizeof(cp));

/* En realidad, como aun no se han inicializado, la memoria a la que


apuntan
los punteros no "nos pertenece", pero podemos preguntar su
tama¤o: */
printf("Tama¤o de lo apuntado por cp: %d\n", sizeof(*cp));
printf("Tama¤o de lo apuntado por ip: %d\n", sizeof(*ip));
}
/
**********************************************************************
******
PROGRAMA: tipos1
AUTOR: Kiko
FECHA: 12.07.94
FINALIDAD: Ilustraci¢n de tipos elementales de datos, constantes y
secuencias de escape.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: Sin requerimientos especiales.
**********************************************************************
******/

/* Ficheros de cabeceras de funciones de librer¡a */


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

/* 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);

printf("Constante decimal (sin signo): %u\n", c1);


printf("Constante decimal (larga): %ld\n", c2);
printf("Constante decimal (larga sin signo): %lu\n", c3);
printf("Constante octal: %o\n", c4);
printf("Constante hexadecimal: %X\n", c5);
printf("Constante de caracter: %c\n", c6);
printf("Constante de caracter: %c\n", c7);
printf("Constante de caracter: %s\n", c8);

printf("Algunas secuencias de escape:\n");


printf("Tabulador:\ttexto\n");
printf("Nueva l¡nea: texto\ntexto\ntexto\n");
printf("sonido\a\n");
printf("backspace\b\n");
printf("comillas\"\n");
printf("backslash\\\n");
printf("Retorno de carro: \r\n");
}
/
**********************************************************************
******
PROGRAMA: tipos2
AUTOR: Kiko
FECHA: 12.07.94
FINALIDAD: Ilustraci¢n de tipos de datos estructurados.
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: Sin requerimientos especiales.
**********************************************************************
******/

/* Ficheros de cabeceras de funciones de librer¡a */


#include <stdio.h> /* Para el printf */
#include <conio.h> /* Para el clrscr */
#include <string.h> /* Para el strcpy */

#define N 2
#define M 3

int vector[N]; /* Un array de N enteros */


static char mensaje[] = "Hola!"; /* Mensaje est tico */
float x[5] = {0, 1.0, 2.0, 3.0, 4.0}; /* Vector de reales */
char colores[3] = {'R', 'G', 'B'}; /* Caracteres */
int matriz[N][M]; /* Array bidimensional */

/* 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.
*/

/* Enumeraci¢n para definir el tipo boolean */


typedef enum {FALSE = 0, TRUE = 1} boolean;

void main()
{
int i;

clrscr();
for (i = 0; i < N; i++)
vector[i] = i;

/* Acceso a los campos de una estructura */


f.dia = 12;
f.mes = 7;
f.anio = 1994;

strcpy(alu1.nombre, "Miguel");
strcpy(alu1.apellido1, "Cervantes");
strcpy(alu1.apellido2, "Saavedra");
alu1.dni = 123456;

printf("Nombre: %s %s %s\n", alu1.nombre, alu1.apellido1,


alu1.apellido2);
printf("D.N.I.: %ld\n", alu1.dni);
}
/
**********************************************************************
******
PROGRAMA: enum
AUTOR: Kiko
FECHA: 05.10.94
FINALIDAD: Ilustrar las enumeraciones
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION:
**********************************************************************
******/

#include <stdio.h>

enum colores {negro = -1, blanco = 7, azul, rojo, cian, verde,


naranja};
void main(void){

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


printf("blanco: %d\n", blanco);
printf("azul: %d\n", azul);
printf("rojo: %d\n", rojo);
}
/
**********************************************************************
******
PROGRAMA: Typedef
AUTOR: Kiko
FECHA: 12.07.94
FINALIDAD: Ilustrar la definici¢n de tipos
HISTORIA:
BIBLIOGRAFIA:
MODO DE UTILIZACION: Sin requisitos especiales
**********************************************************************
******/

#include <stdio.h>

#define N 100

/*
struct alfa {
int c1;
char c2;
};

typedef struct alfa prueba;


*/

typedef unsigned char byte; /* Definici¢n del tipo byte */


typedef int[100] vectores; /* Vectores es un array de N
elementos */

/* Enumeraci¢n para definir el tipo boolean */


typedef enum {FALSE = 0, TRUE = 1} boolean;

main()
{
byte b;
int i;
vectores v;
prueba s;

for (b = 1; b < 300; b++) /* Bucle infinito porque b nunca


*/
printf("i: %i\n", b); /* a valer 300
*/
for (i = 1; i < N; i++)
v[i] = i;

}
/
**********************************************************************
******
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);

printf("N£mero (formateando como caracter): %d\n", c);

/* Una forma correcta de conseguir lo mismo: Almacenar el valor del


caracter
en un entero mediante un type cast: Aqu¡ se indica al compilador de C
que
interprete c como un entero y almacene en la variable i su valor.
*/

i = (int)c;
printf("N£mero (formateando como entero): %d\n", i);

/* La que sigue ser¡a otra forma correcta de hacerlo (hacer


directamente el
type cast: */

printf("N£mero (formateando como entero): %d\n", (int)c);

printf("Tama¤o del vector1: %d\n", sizeof(vector1));


printf("Tama¤o del vector2: %d\n", sizeof(vector2));

printf("Caracter central: %d\n", vector2[1]);

/* Como la cadena 'vector2' no est terminada con '\0', printf no la


escribe
correctamente: */
printf("Vector2: %s\n", vector2);
}

/
**********************************************************************
******
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>

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


int i; /* contador */

clrscr();
if (argc < 2) {
printf("Modo de uso: args par_1 par_2 par_3 ... par_N\n");
exit(0);
}

printf("N£mero de par metros introducidos: %d\n", argc - 1);


printf("Los argumentos introducidos son:\n\n");
for (i = 0; i < argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
printf("\n\nN¢tese que argv[0] es el nombre del propio programa.\n");
}

/
**********************************************************************
******
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>

int a1 = 1; /* Ambito en todo el programa */

/
**********************************************************************
******/
void f(void){
int a3 = 3; /* Ambito en el cuerpo de la funci¢n */

printf("A1: %d\n", a1);


printf("A2: %d\n", a2);
printf("A3: %d\n", a3);
printf("A4: %d\n", a4);

}
/
**********************************************************************
******/
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 */

printf("A1: %d\n", a1);


printf("A2: %d\n", a2);
printf("A3: %d\n", a3);
printf("A4: %d\n", a4);
break;
}
printf("A1: %d\n", a1);
printf("A2: %d\n", a2);
printf("A3: %d\n", a3);
printf("A4: %d\n", a4);
}

/
**********************************************************************
******
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;

printf("Introduzca una cadena de caracteres, un n£mero entero y


uno real. \
Compruebe que los valores se pueden introducir todos en la
misma l¡nea,\
separados por espacios o bien en l¡neas separadas: Se
interpretan los\
retornos de carro como caracteres de espaciado.\nVea tambi‚n
que scanf\
devuelve el n£mero de campos que ha le¡do correctamente.");

printf("\n\nIntroduzca la entrada solicitada: ");


valor = scanf("%s %d %f", letras, &entero, &real);
printf("\nCadena: %s\n", letras);
printf("\nEntero: %d\n", entero);
printf("\nReal: %f\n", real);
printf("Valor devuelto por scanf: %d\n", 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;

printf("Introduzca una cadena que contenga espacios en


blanco.\n");
printf("\n\nIntroduzca cadena: ");
valor = scanf("%s", letras);
printf("\nCadena le¡da: %s\n", letras);
printf("Valor devuelto por scanf: %d\n", 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 convert(char *string) {


return atoi(string);
}

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;

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


v[i] = 10;

while (i < 100)


suma += v[i++];
media = suma / 100;
printf("Media: %d\n", media);
}

/
**********************************************************************
******
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'

typedef enum {FALSE = 0, TRUE = 1} boolean;

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


{
FILE *f; /* File handler */
int c, /* Caracter le¡do del fichero */
nl, nw, nc; /* Contadores de l¡neas, palabras y caracteres
*/
boolean inword; /* Indica si se est procesando una palabra */

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);
}

if ((f = fopen(argv[1], "r")) == NULL) {


printf("Error trying to open %s as input\n", argv[1]);
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;

/* N¢tese que se pueden hacer cosas como ‚sta: */


printf("Componente v[-1]: %d\n", *(v - 1));
/* Naturalmente el valor que se escribe es "basura" */

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


printf("Componente %d: %d\n", i, v[i]);
printf("\n");

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


printf("Componente %d: %d\n", i, *(p + i));
printf("\n");

/* Cambiamos el valor al que apunta p: */


p = p + 2;
for (i = 0; i < size; i++)
printf("Componente %d: %d\n", i, *(p + i));
printf("\n");
/* Las dos £ltimas componentes que se escriben son "basura" */

/* Compru‚bese que no se puede cambiar la direcci¢n de v: v se


considera
un puntero a otros efectos, pero no se puede cambiar
la direcci¢n a la
que apunta: esa direcci¢n es asignada por el
compilador. Tratar de
compilar la linea siguiente sin comentarios: */

/* 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);


void f2(int **p);

/
*=====================================================================
=====*/
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)();

puntero_a_funcion = sumar_uno; /* Lo que se igualan son


direcciones */

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>

#define N 1000 /* Tama¤o del vector a ordenar


*/
#define M 50 /* Tama¤o del registro (salvo la
clave) */

typedef unsigned claves;


typedef struct {
claves clave;
char resto[M];
} items;

items v[N];

void inicializa(void);
void escribe(void);

/
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::*/
void inicializa(void) {
unsigned i;

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


v[i].clave = rand();
}
}
/
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::*/
void escribe(void) {
unsigned i;

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


printf("v[%u] = %i\n", i, v[i].clave);
}
/
*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::*/
void quicksort(unsigned iz, unsigned de) {
register unsigned i, j;
claves pivot;
items temp;

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;
}

CAPITULO 9: BIBLIOTECAS DE FUNCIONES

El lenguaje C, C++ contiene numerosas funciones, cuando se emplean


funciones de esta biblioteca estandar, se incrementa la transportabilidad de los
programas.

Las funciones estandar se dividen en grupos, todas las funciones que


pertenecen al mismo grupo estan declaradas en el archivo de cabecera (aquel
que dice xxx.h), la letra "h" significa header en inglés y es lo que se llama
cabecera.

Para incluir alguna función perteneciente a estas cabeceras debemos escribir


líneas de código como se muestra de ejemplo:

#include

He disenado esta tabla para que estudiemos las bibliotecas de funciones,


obviamente son las que he encontrado en mis libros y sistemas.

BIBLIOTECAS Y DESCRIPCIONES DE USO


Nombre de
Descripcion
Biblioteca
Es proporcionar una definicion de la macro assert, que
assert.h
imprime un mensaje de error y aborta el programa
Existen funciones para asignar, liberar memoria, u obtener
alloc.h
informacion de bloques de memoria.
Son funciones que nos permiten conocer la naturaleza de un
ctype.h caracter, o bien para convertir de mayusculas a minusculas
y viceversa; y valores enteros a codigos ASCII.
Esto permite ordenar, crear, modificar, mover y eliminar
dir.h
directorios
errno.h Representa los numeros de error, despues que ocurre un
error se puede consultar el valor de la varianble del sistema
deerrno para obtener mas informacion sobre ese error.
float.h Define los limites de los tipos de coma flotante
limits.h Define los limites de los diferentes tipos de enteros
Contiene las funciones matematicas estandar utilizadas en
math.h
C y C++
setjmp.h Define el tipo de jmp_buf para algunas funciones.
signal.h Contiene funciones de estado.
Define funciones que pueden ser llamadas con diferentes
stdarg.h numeros de argumentos, de modo que se pueda escribir f(a)
y f(a,b).
stdef.h Se definen algunos tipos especiales
Incorporan las funciones de Entrada - Salida E/S estandar,
stdio.h
tipos y macros
Declara funciones que son utiles para diferentes propositos,
stlib.h
en especial de busqueda y ordenacion.
Este archivo contiene funciones para manejo de cadenas de
string.h
caracteres.
time.h Contiene funciones relativas a fechas y horas
Funciones Encontradas en las Bibliotecas
Biblioteca
Nombre
# Tipo a la cual Sintaxis Descripción Ejemplo
de función
pertenece
Devuelve el valor absoluto
1 abs(i) int stdlib.h int abs(int i); x = abs(-7) // x es 7
de i
Devuelve el arco coseno de angulo = acos(0.5); // angulo devuelto es
2 acos(d) double math.h double acos(double d);
d phi/3
angulo = asin(0.707); // aproximadamente
3 asin(d) double math.h double asin(double d); Devuelve el arco seno de d
phi/4
Devuelve la arco tangente
double atan(double d); de d. Calcula el arco
4 atan(d) double math.h long double tanl(long tangente del argumento x. angulo atan(1.0); // angulo es phi/4
double d); Requiere el llamado de la
biblioteca complex.h
double atan(double d1, Devuelve el arco tangente
5 atan(d1, d2) double math.h angulo = atan(y, x)
double d2); de d1/d2
Convierte la cadena s a una double x;
double atof(const char cantidad de doble precisión. char *cad_dbl = "200.85"; ...
6 atof(s) double stdlib.h
*cadena) Requiere el llamdo de la x=atof(cad_dbl); // convierte la cadena
biblioteca math.h "200.85" a valor real
7 atoi(s) int stdlib.h int atoi(const char Convierte la cadena s a un int i;
*cadena) entero. char *cad_ent="123";
La cadena debe tener el ...
siguiente formato: i=atoi(cad_ent); //convierte la cadena "123"
[espacio en blanco][signo] al entero 123
[ddd] (siendo obligatorio
los digitos decimales).
Convierte la cadena s a un
entero largo. long int i;
La cadena debe tener el char cad_ent="9876543";
long atol(const char
8 atol(s) long stdlib.h siguiente formato: ...
*cadena);
[espacio en blanco][signo] i=atol(cad_ent); //convierte la cadena
[ddd] (siendo obligatorio "9876543" al entero largo
los digitos decimales).
Reserva memoria para una
formación de n elementos ,
cada uno de s bytes.
malloc.h y
Devuelve un puntero al
stdlib.h
void *calloc(size_t n, principio del espacio long *buffer
9 calloc(n, s) void(puntero) o bien
size_t s); reservado. buffer=(long *) calloc(40, sizeof(long));
alloc.h y
Si no existente bastante
stdlib.h
espacio para el nuevo
bloque o bien n o s es 0,
calloc devuelve nulo.
Devuelve un valor
10 ceil(d) double math.h double ceil(double d); redondeado por exceso al redondeo=ceil(5.1); //redondeo es 6
siguiente entero mayor
double cos(double d);
11 cos(d) double math.h Devuelve el coseno de d coseno_x=cos(1.6543)
complex cos(complex d);
double cos(double d); Devuelve el coseno d=1.00;
12 cosh(d) double math.h
complex cos(complex d); hiperbólico de d printf("d=%f.\n\n,d);
13 difftime(11, double time.h double difftime(time_t Devuelve la diferencia de time_t inicio, fin;
12) hora2, time_t hora1) tiempo 11(hora2) - clrscrl();
12(hora1) , donde 11 y 12 inicio=time(NULL);
representan el tiempo delay(5000)
transcurrido despues de un fin=time(NULL)
tiempo base (ver función print("Diferencia en segundos: %f\n",
time) difftime(inicio,fin));
Cierra todos los archivos y
buffers y termina el
programa. El valor de u es
14 exit(u) void stdlib.h void exit(int estado) exit(0);
asignado por la funcion
para indicar el estado de
terminación.
Eleve e a la potencia d
d=100.00;
double exp(double d); (e=2,7182818... es la base
15 exp(d) double math.h y=exp(d);
complex exp(complex d) del sistema de logaritmos
printf("El exponencial de x=%f.\n\n",y);
naturales (neperianos))
Devuelve el valor absoluto
16 fabs(d) double math.h double fabs(double d); y=fabs(-7.25); // y vale 7.25
de d
Cierra el archivo f.
Devuelve el valor 0 si el
17 fclose(f) int stdio.h int fclose(FILE *f); int fclose(FILE "archivo");
archivo se ha cerrado con
exito.
Determina si se ha
encontrado un fin de
18 feof(f) int stdio.h int feof(FILE *f); archivo. si es asi, devuelve feof(fichen);
un valor distinto de cero, en
otro caso devuelve 0
Lee un caracter del archivo
19 fgetc(f) int stdio.h int fgetc(FILE f); c+fgetc(fp)
f
char *fgets(char s, int s, Lee una cadena s, con i
20 fegts(s, i, f) char(puntero) stdio.h fgets(caddemo, 80, fp);
FILE *f); caracteres, del archivo f
Devuelve un valor
21 floor(d) double math.h double floor(double d); redondeado por defecto al x=floor(6.25); // x vale 6
entero menor mas cercano
Devuelve el resto de d1/d2
fmod(d1, double fmod(double d1,
22 double math.h (con el mismo signo que resto=fmod(5.0,2.0); // resto igual a 1.0
d2) double d2);
d1)
Abre un archivo llamado s1,
del tipo s2. Devuelve un
puntero al archivo. *

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

Copia la cadena de char *s1="Pepe Luis";


strcpy(s1, char *strcpy(char s1, const
67 char string.h caracteres s2 en la cadena char b[12];
s2) char s2);
s1 strcpy(s2,s1);
cout <<s2<< '\n';

size_t strlen(const char Devuelve el numero de longitud=strlen(nombre);


68 strlen(s) int string.h
*s); caracteres de una cadena char s[81]="Cadena demo';
printf("La longitud de s es: %d\n" strlen(s));
Pone todos los caracteres de
char *strset(char *cad, int char *cad="----";
69 strset(c, s) char(puntero) string.h s a c (excluyendo el caracter
c); strset (cad,'x'); // cad es ahora xxxx
nulo del final \0)
Pasa la orden al sistema
operativo. Devuelve cero si
la orden se ejecuta
70 system(s) int string.h system(comd); system(dir);
correctamente; en otro caso
devuelve un valor distinto
de cero, tipicamente -1.
71 tan(d) double math.h double tan(double d); Devuelve la tangente de d y=tan(x);
Devuelve la tangente
72 tanh(d) double math.h double tanh(double d); a=tanh(x);
hiperbolica de d
Devuelve el numero de
segundos transcurridos
73 time(p) long int time.h time_t time(time_t *h); time(&hora);
despues de un tiempo base
designado
Convierte el valor del
74 toascii int ctype.h int toascii(int c); c=toascii(entero);
argumento a ASCII
ctype.h o Convierte una letra a
75 tolower int int tolower(int c); c=tolower('s'); //c se convierte en 's'
stdlib.h minuscula
ctype.h o Convierte una letra a
76 toupper int int toupper(int c); c=toupper('s'); //c se convierte en 'S'
stdlib.h mayuscula

Você também pode gostar