Académique Documents
Professionnel Documents
Culture Documents
Este tutorial es gratuito, puedes distribuirlo libremente siempre que sea en forma gratuita y
en forma completa sin alteración alguna. La distribución en cualquier medio de este tutorial
comercialmente queda estrictamente prohibida sin consentimiento por escrito del autor.
Copyright 2003-2005, todos los derechos reservados por Rogelio Cesar Rodriguez Cervantes
Informacion de contacto:
e-mail 1 : cesarrdz@gmail.com
e-mail 2 : cesarrdz@excite.com
Sito web : http://cesar.crbyte.com
Visita:
http://cesar.crbyte.com para mas tutoriales de C++, Base de datos, programas con codigo
fuente, etc.
http://crbyte.com para juegos de computadora que puedes bajar gratis
1
Contenido
Prefacio 4
1. Fundamentos del lenguaje 5
Funciónes 5
Identificadores 6
Tipos de datos 6
Declaración de variables 6
Funcion printf 7
Constantes 9
Construcción cast 10
Constantes simbólicas 11
Operadores 11
Conversiones de tipo 13
Funcion scanf 14
Precedencia y orden de evaluación 15
2. Control de flujo 16
Sentencia if-else 16
Iteraciones while y for 17
Sentencia break 18
Saltos y etiquetas 18
Sentencia switch 19
Iteración do-while 20
3. Arreglos y cadenas de caracteres 22
Arreglos unidimensionales 22
Cadenas de caracteres 24
Funciones mas comunes para manejo de cadenas 25
Arreglos bidimensionales 26
4. Funciones 29
Tipos de variables: Parte 1 29
Funciones 30
Reglas de alcance de funciones 31
Argumentos de funciones: Llamada por valor 32
Archivos de encabezados 33
5. Apuntadores 34
Definición de apuntadores 34
Indireccion 35
Llamadas por apuntadores 36
Aritmética de apuntadores 37
Apuntadores y arreglos 38
Apuntadores a caracteres 39
Manejo dinámico de memoria 42
Arreglos de apuntadores 43
Indireccion simple y múltiple 44
Diferiencias arreglos bidimensionales y de apuntadores 46
Argumentos para main 46
6. Estructuras 48
Definición 48
Arreglo de estructuras 50
2
Paso de estructuras a funciones 53
Apuntadores a estructuras 55
7. Archivos 58
Entrada y salida 58
Corrientes de flujo 58
Función fopen 58
Función fclose 59
Función getc 59
Función putc 61
Función ferror 62
Función fwrite 64
Ejemplo de fread 64
8. Temas avanzados 68
Tipos de variables: Parte 2 68
Operadores: Parte 2 69
Definición de tipos: 74
Funciones recursivas 76
9. Bibliografia 79
3
Prefacio
El lenguaje C es de propósito general y se clasifica relativamente de "bajo nivel".
Fue creado para poder manejar todos los recursos del computador en uso, así como
facilitar el desarrollo de sistemas: pocas restricciones, código rápido y eficaz.
Por ejemplo veamos PASCAL; este fue diseñado por el profesor WRITH para
enseñar la programación estructurada, no para aprovechar todos los recursos ni
para realizar grandes sistemas.
Por lo tanto al desarrollar el C no se tuvo en mente facilitar la programación sino
aprovechar al máximo los recurso disponibles.
El origen del lenguaje C empezó con un lenguaje llamado BCPL , desarrollado por
Martín Richards; que a la vez influyo en un lenguaje llamado B inventado por Ken
Thompson.
Basándose en este ultimo Dennis Ritchie desarrollo el C, y fue implementado por
primera vez en una PDP-11 que usaba el sistema operativo UNIX.
Agradecimiento
A mis Padres Rogelio Rodríguez y Rosario Cervantes. Por haberme apoyado para
estudiar la carrera de Ingeniería en Sistemas Computacionales.
4
1
Fundamentos del lenguaje
Funciones
Un programa en C puede verse como un grupo de blocs construidos llamados
funciones.
Una función es una o mas instrucciones en C designadas para una tarea especifica.
Similares a los procedimientos y funciones en PASCAL.
/* Programa : Primer.c */
/* Descripcion: Escribe un mensaje en pantalla */
#include<stdio.h>
main() {
printf("Este es mi primer programa en C\n");
}
/* */
Enmarcan comentarios. Se usan en cualquier lugar del programa.
#include <stdio.h>
La palabra include especifica la inclusión de un archivo, en este caso del archivo
stdio.h, el cual define prototipos de funciones y macros diversas.
main()
Todo programa tiene una función especial llamada main la cual indica donde
empieza la ejecución. Esta función debe aparecer solo una vez en el programa.
{}
Las llaves enmarcan las sentencias o proposiciones que integran la función;
análogas al begin y end de PASCAL.
printf()
El sistema C contiene una biblioteca estandard de funciones para usarse en los
programas; esta función imprime en pantalla una cadena de caracteres.
'\n'
Esta secuencia de caracteres significa Nueva Linea; representa solo un carácter.
Printf no efectúa salto de linea automático.
Ejercicio: Datosper.c
Escriba un programa que despliegue sus datos personales en pantalla.
5
Identificadores
El lenguaje C define identificadores con los nombres que se utilizan para
referenciar variables, funciones, etiquetas y otros objetos definidos por el usuario.
Reglas
1.- Debe Comenzar con una letra
2.- Formarse con letra, dígitos y guiones bajos
3.- El tamaño no debe exceder de 31
Tipos de datos
TIPO BITS
char 8
int 16
float 32
double 64
void 0
Modificadores de tipo.
Excepto para void, los tipos de datos básicos tienen varios modificadores que los
proceden. Se usa un modificador para alterar el significado de un tipo base para
encajar con las necesidades diversas mas precisamente.
signed
unsigned
long
short
Declaración de variables
Todas las variables deben de ser declaradas antes de utilizarlas, aunque ciertas
declaraciones se realizan implícitamente por el contexto. Una declaración
especifica un tipo , y le sigue una lista de una o mas variables de ese tipo.
Ejemplo:
int a, x;
char c, linea[10];
También:
int a;
int x;
char c;
char linea[10];
6
Las variables también se pueden inicial izar en su declaración.
Ejemplo:
char tabulador = '\t';
int i = 0;
float x = 3.4;
/* Programa : DECVAR.C
Descripcion: Declaracion de variables*/
#include <stdio.h>
main() {
int n, c;
c = 2;
n = c * c;
printf("\nEl cuadrado de 2 es %d ", n);
}
printf()
#include <stdio.h>
int printf(const char *formato ...);
Da formato e imprime texto en el flujo de salida estandard.
Descripcion:
El formato apunta a un string que contiene texto, constantes de caracter, y una o
mas especificaciones de conversion.
7
Variaciones de printf().
Numéric Significado
o
%d Decimal (base 10)
%o Octal (base 8)
%x Hexadecimal (base 16)
%u Decimal sin signo.
%e Notación científica (double o float 1.23E23)
%f Decimal (double o float 1.23E23)
%g %e o %f selecciona el mas corto.
String. Significado
%c Un solo carácter.
%s Conjunto de caracteres (string).
Ejercicio: Datosper2.c
Realize un programa que imprima sus datos personales centrados lo mas posible en
pantalla, utilizando las constantes de carácter no imprimibles, y dando efectos de
sonido utilizando las mismas constantes.
/*Programa : sizeof.c
Descripción: Ejemplo de la función sizeof
Nota.......: Genera 2 warnings (BC++ 3.1/Opcion ANSI):
a i, j se le asigna valores y no son usados (i y j).
No hay problema. Solo es un ejemplo de los bytes usados
cuando se suma un int y un float en memoria.
*/
#include <stdio.h>
#include <conio.h> /* clrscr() */
int main() {
int i;
float j;
8
i = 9;
j = 1.0;
clrscr();
printf("\n j + i %d bytes ", sizeof(j+i));
printf("\n char %d bytes ", sizeof(char));
printf("\n int %d bytes ", sizeof(int));
printf("\n short %d bytes ", sizeof(short));
printf("\n unsigned %d bytes ", sizeof(unsigned));
printf("\n long %d bytes ", sizeof(long));
printf("\n float %d bytes ", sizeof(float));
printf("\n double %d bytes ", sizeof(double));
return 0;
}
Constantes
Las constantes de C son los valores fijos que el programa no puede alterar.
Las constantes de carácter están encerradas entre apóstrofes.
Ejemplo:
'a', '%'
'a' es una constante de carácter compuesta por la letra a y "a" es una cadena de
caracteres compuesta por la letra a y el carácter nulo y esta formada de dos
elementos.
"" es una cadena nula con un elemento (\0).
EJEMPLOS DE CONSTANTES.
123L constante long
123.3 constante float
/*Programa: TIPOS.C
Desc. : Ejemplo de constantes*/
#include <stdio.h>
main(){
printf("\n%f", 1/2);
9
printf("\n%f", 1.0/2);
}
Construcción cast
Se usa para forzar la conversión explícita del tipo de una variable.
Uso:
(tipo) expresión
La expresión se convierte al tipo citado.
Ejemplo:
La función de la biblioteca estandard sqrt() espera que se le pase un argumento de
tipo double, si no es as¡ producirá resultados sin significado.
int n;
sqrt( (double) n);
/*Programa: CAST.C
Desc. : Demostracion de la construccion cast*/
#include <stdio.h>
main(){
printf("\n%f", (float)1/2);
printf("\n%f", 1.0/2);
}
getchar()
#include <stdio.h>
int getchar(void)
Lee un caracter de el flujo de entrada estandard.
Descripcion:
getchar lee y regresa un caracter del archivo o dispositivo asociado con stdin.
/* Programa: GETCHAR.C
Desc. : Uso del getchar, lee un caracter de la entada y despliega
el caracter junto con su numero assci*/
#include <stdio.h>
main(){
char c;
c = getchar();
printf("\n%c %d", c, c);
}
10
Ejercicio: Vecinos.c
Escriba un programa vecinos.c que lea un carácter de la entrada estandard y
despliegue el carácter anterior, el leído y el siguiente.
Constantes simbólicas
#define
Mediante esta construcción al principio de un programa se puede definir un nombre
simbólico o constante simbólica como una determinada cadena de caracteres.
/*Programa: PASCUAL.C
Desc. : Emulacion del PASCAL mediante el preprocesador
*/
#include <stdio.h>
PROGRAM
BEGIN
WRITE("Hola");
END
/*Programa: UNALINEA.C
Desc. : Demostracion del #define
*/
#include <stdio.h>
HOLA
El preprocesador remplaza todas las apariciones no entre comillas del nombre por
su cadena correspondiente.
Ejercicio:
Investigar todas las palabras reservadas del preprocesador, su sintaxis y un ejemplo
de cada una.
Operadores
Operadores aritméticos.
Operador Acción
- resta y menos unario
+ suma
* multiplicación
/ división
11
% modulo de división
-- decremento
++ incremento
Operadores relaciónales.
Operador Acción
> mayor que
>= mayor que o igual que
< menor que
<= menor o igual que
== igual
!= no igual
El doble signo igual == es la notación de C para "es igual a". Este símbolo se
distingue de la condición de igualdad del simple = empleado en las asignaciones.
Las asignaciones son aproximadamente 2 veces mas frecuentes que la
comprobación de igualdad en típicos programas de C; por esto es adecuado que el
operador ocupe la mitad de espacio.
Operadores lógicos.
Operador Acción
&& and
|| or
! not
Incremento decremento
++ --
Ejemplo:
++n incrementa la variable n en 1. (op. prefijos)
n++ incrementa la variable n en 1. (op. posfijos)
--n decrementa la variable n en 1. (op. prefijos)
n-- decrementa la variable n en 1. (op. posfijos)
Equivalentes.
++n n=n+1
--n n=n-1
12
/*Programa : mas_mas.c
Descripción: Desmostracion de los operadores unarios ++ y --
*/
#include <stdio.h>
int main() {
int i, j;
i = 10;
j = 20;
printf("\n\ni %d, j %d", i, j);
printf("\ni++ %d", i++);
printf("\n++j %d", ++j);
i++;
++j;
printf("\n\ni %d, j %d", i, j);
return 0;
}
Conversiones de tipo
Cuando se mezclan constantes y variables de diferentes tipos en una expresión, C
las convierte en el mismo tipo. El compilador de C convertirá todos los operandos
al tipo del operando mas grande en una operación según la base de esta operación.
c = 65;
i = 10;
f = i + c;
scanf()
#include <stdio.h>
int scanf(const char *formato ...);
Lee e interpreta texto desde el flujo de entrada estandard.
Descripcion:
scanf lee caracteres desde el flujo de entrada estandard y usa el string formato para
interpretar que es leído en los tipos de datos correspondientes.
/* Programa: CONDOLAR.C
Desc. : Convierte pesos a dolares, pide el tipo de cambio*/
#include <stdio.h>
main(){
int pesos, cambio;
float dolares;
Ejercicio: Dolpesos.c
Realize un programa que convierta una cantidad en dolares a pesos. Pida el tipo de
cambio
14
Precedencia y orden de evaluación de operadores.
Operador Asociatividad
() [] -> . izquierda a derecha
! ~ ++ -- - (tipo) * & sizeof derecha a izquierda
* / % izquierda a derecha
+ - izquierda a derecha
<< >> izquierda a derecha
< <= > >= izquierda a derecha
== != izquierda a derecha
& izquierda a derecha
^ izquierda a derecha
| izquierda a derecha
&& izquierda a derecha
|| izquierda a derecha
?: derecha a izquierda
= += -= etc. izquierda a derecha
, derecha a izquierda
15
2
Control de flujo
Las sentencias o proposiciones de flujo de un lenguaje especifican el orden que se
realizan las computaciones.
if-else
Para tomar decisiones.
Forma general:
if (condición)
sentencia-1;
else
sentencia-2;
Nota:
El lenguaje C no hace restricción el tipo de expresiones a solo las que invocan
operadores relacionales y lógicos.
Todo lo que se requiere es que la expresión evaluada de cero o no cero.
/* Programa : divide.c
Descripcion: Divide el primer numero por el segundo */
#include <stdio.h>
int main() {
int a, b;
16
Iteraciones while y for
Forma general:
while (condición) proposición;
/* Programa : tolower.c
Descripcion: Muestra el uso de la funcion tolower */
#include <stdio.h>
#include <ctype.h>
int main() {
int c;
c = getchar();
while (c != EOF) {
printf(" %c ", tolower( c ) );
c = getchar();
}
return 0;
}
Forma general:
for (inicialización; condición; incremento)
proposición;
/* Programa : lineas.c
Descripcion: Muestra el uso del for*/
#include <stdio.h>
#define NUMLIN 24
int main() {
int i;
return 0;
}
En los dos, el ciclo se ejecuta hasta que condición sea falsa (cero).
inicialización;
while (condición) {
proposición;
incremento;
}
Ejercicio: Lineas2.c
Realizar el programa lineas.c utilizando la iteración while.
Ejercicio: Toupper.c
Hacer el programa tolower.c utilizando la iteración for.
Sentencia break
Proporciona una salida forzada de for, while, do, en la misma forma que
switch.
Una sentencia break obliga a una salida inmediata del ciclo ( switch) mas
interior.
Ejemplo:
Saca raíz cuadrada mientras no se de un numero negativo.
for (; ;) {
scanf("%f", &n);
if (n < 0.0)
break;
printf("\n %f", sqrt(n));
}
/* la sentencia break salta hasta aquí */
Saltos y etiquetas
goto
El goto requiere una etiqueta para funcionar. Una etiqueta es un identificador
valido de C que se sigue por dos puntos. Normalmente no es necesario y es fácil de
prescindir de el. Sin embargo hay ocasiones en que puede se útil.
/* Programa : goto.c
Descripcion: Saca ra¡z cuadrada mientras no se de un numero negativo */
#include <stdio.h>
#include <math.h> /* sqrt() */
int main() {
float n;
while (1) {
scanf("%f", &n);
if (n < 0.0)
18
goto alerta;
printf("\n %f\n", sqrt(n));
}
alerta: printf("\nHa ocurrido un valor negativo ");
return 0;
}
Sentencia switch
Herramienta especial para decisiones múltiples que comprueba si una expresión
iguala uno entre varios valores constantes, y se bifurca a partir de ellos.
Forma General:
switch (variable) {
case constante1:
secuencia de sentencias;
case constante2:
secuencia de sentencias;
break;
case constante3:
secuencia de sentencias;
break;
.
.
.
default:
secuencia de sentencias;
}
Reglas.
1.- El switch difiere del if porque la primera solo puede
comprobar por igualdad, mientras que la expresión
condicional del if puede ser de cualquier tipo.
2.- No pueden tener dos constantes case con idénticos
valores en el mismo switch. Una sentencia switch que
esta encerrada por otro switch puede tener constantes
case que son las mismas.
case
Actúa como una etiqueta.
break
Opcional dentro de la sentencia switch. Se usa para terminar la secuencia
que esta asociada con cada constante. Si se omite, la ejecución continuara
en las sentencias del siguiente case hasta encontrar un break, un return
o el final del switch.
19
default
Es opcional y se ejecuta si no se satisface ninguna opción.
/* Programa : EFECTOS.C
Descripcion: Muestra el uso de la sentencia switch*/
#include <stdio.h>
#include <dos.h> /* delay() */
#include <conio.h> /* _setcursortype() */
#define ESPERA 50
#define VECES 30
int main() {
char op;
int i;
clrscr();
printf("\n***** MENU *****");
printf("\n1 Sonido");
printf("\n2 Animacion");
printf("\nOpcion? ");
op = getchar();
switch(op) {
case '1':
printf("\a\a");
break;
case '2':
printf("\t\t\t\t"); _setcursortype(_NOCURSOR);
for (i=0; i < VECES; i++) {
printf("|"); delay(ESPERA);
printf("\b/"); delay(ESPERA);
printf("\b-"); delay(ESPERA);
printf("\b\\\b"); delay(ESPERA);
}
_setcursortype(_NORMALCURSOR); break;
default:
printf("\nOpcion no implementada");
}
return 0;
}
Ejercicio: Digitos.C
Escriba un programa que lea un carácter del teclado y si se trata de un numero
despliegue el numero con letra, si no es un numero mencionarlo.
Iteraciones do-while
Hace la comprobación al final después de cada pasada a través del cuerpo del
ciclo. Y este se ejecuta al menos una vez.
Forma general:
do
20
proposición;
while (condición);
/* Programa : MENUEFE.C
Descripcion: Efectos en un menu dentro del do .. while*/
#include <stdio.h>
#include <dos.h> /* delay() */
#include <conio.h> /* _setcursortype() */
#define ESPERA 50
#define VECES 20
int main() {
char op;
int i;
do {
clrscr();
printf("\n***** MENU *****");
printf("\nSonido");
printf("\nAnimacion");
printf("\nFin");
printf("\nOpcion? ");
op = getchar();
switch(op) {
case 'S':
case 's':
printf("\a\a");
break;
case 'A':
case 'a':
printf("\t\t\t\t"); _setcursortype(_NOCURSOR);
for (i=0; i < VECES; i++) {
printf("|"); delay(ESPERA);
printf("\b/"); delay(ESPERA);
printf("\b-"); delay(ESPERA);
printf("\b\\\b"); delay(ESPERA);
}
_setcursortype(_NORMALCURSOR); break;
}
} while (op != 'F' && op != 'f');
return 0;
}
Ejercicio: Digitos2.C
Modifique el programa del ejercicio Digitos.c para que termine hasta que se ingrese
un 'X'. Lea un carácter del teclado y si se trata de un numero despliegue el numero
con letra, si no es un numero mencionarlo.
21
3
Arreglos y cadenas de caracteres
Arreglos unidimensionales
Forma general:
tipo nombre_variable[tamaño]
/* Programa: INVERSO.C
Desc. : Pide una lista de enteros y los despliega en orden inverso*/
#include <stdio.h>
int main(){
int i, lista[10];
return 0;
}
En C todos los arreglos usan el cero como índice del primer elemento.
Ejemplo:
int lista[10]
return 0;
}
/* Programa: BUSCA.C
Desc. : Pide una lista de enteros y un numero para buscarlo en la lista*/
#include <stdio.h>
#include <conio.h>
#define LIMITE 5
int main(){
int i, n, lista[LIMITE];
clrscr();
printf("Ingresa %d numeros enteros\n", LIMITE);
for (i=0; i < LIMITE; i++) {
printf("Lista[%d] = ? ", i);
scanf("%d", &lista[i]);
}
printf("\nIngresa el numero a buscar ");
scanf("%d", &n);
for (i=0; i < LIMITE; i++)
if (n == lista[i])
break;
if (i == LIMITE)
printf("\nEl numero no se encuentra en la lista");
else
printf("\nEl numero se encuentra en la posicion %d", i);
return 0;
}
Ejercicio: Menor.c
Realice un programa que:
a) Pida diez números enteros y los almacene en un arreglo
b) Busque el numero menor y el numero mayor
c) Despliegue el numero menor y el numero mayor
Ejercicio: Ordena1.c
Hacer un programa que:
a) Pida diez números enteros y los almacene en un arreglo
b) Los ordene de menor a mayor
c) Despliegue el arreglo
23
Cadenas de caracteres
Una cadena de caracteres consiste en un arreglo de caracteres terminado en un
nulo. Un nulo se especifica como '\0' y es cero.
Si se quiere definir un a cadena de 10 elementos se debe definir de 11 para
soportar el carácter nulo.
Ejemplo.
char str[11];
Una constante de cadena es una lista de caracteres que se encierran entre comillas.
Ejemplo.
"HOLA"
/* Programa: CADENA.C
Desc. : Cadenas de caracteres */
#include <stdio.h>
#include <conio.h>
int main() {
char s[11];
char s2[] = {'h', 'o', 'l', 'a', '\0'};
char s3[] = "HOLA A TODOS";
char s4[10];
clrscr();
puts("\nIngresa una cadena de caracters: ");
gets(s);
puts(s);
putchar('\n');
puts(s2);
putchar('\n');
puts(s3);
printf("\n%s\n", s3);
s3[5] = '\0';
printf("\n%s\n", s3);
/*s4 = "todos"; <-- esto no esta permitido al menos que s4 haya sido definido como un
apuntador */
return 0;
}
Ejercicio: Printstr.c
Escriba un programa que lee una cadena de caracteres de la entrada estandard y la
imprima en la salida estandard, utilizando la función putchar.
24
Funciones de la biblioteca estandard mas comunes para
el manejo de cadenas de caracteres
strcpy()
formato:
strcpy(destino, fuente)
Copia el contenido de la cadena fuente a la cadena destino.
La cadena destino debe ser lo suficientemente grande para contener la cadena
fuente. (Si no es as¡ producirá resultados inesperados en la ejecución del
programa).
strcat()
formato:
strcat(destino, fuente)
Añade fuente al final de destino.
/* Programa: STRCPY.C
Desc. : Muestra funciones de manejo de Cadenas de caracteres */
#include <stdio.h>
#include <string.h> /* strcpy(), strcat() */
int main() {
char s1[20], s2[10];
strcpy(s1, "hola");
strcpy(s2, " a todos");
strcat(s1, s2);
printf("\n%s", s1);
return 0;
}
strcmp()
formato:
strcmp(s1, s2)
Compara dos cadenas y devuelve 0 si son iguales.
Si s1 es lexicográficamente mayor que s2, entonces la función devuelve un numero
positivo; si s1 es menor que s2, devuelve un numero negativo.
/* Programa: STRCMP.C
Desc. : Muestra funciones de manejo de Cadenas de caracteres */
#include <stdio.h>
#include <string.h> /* strcmp() */
int main() {
char s[80];
if (strcmp(s, "clave"))
printf("\nPalabra de acceso invalida");
return 0;
}
strlen()
formato:
strlen(s);
Devuelve la longitud de la cadena s.
/* Programa: STRLEN.C
Desc. : Muestra funciones de manejo de Cadenas de caracteres */
#include <stdio.h>
#include <string.h> /* strlen() */
int main() {
char s[80];
printf("\Cadena: ");
gets(s);
printf("\nLonguitud: %d", strlen(s));
return 0;
}
Ejercicio:
Escriba un programa que lea una cadena de caracteres de la entrada estandard la
convierta a mayúsculas, y la imprima en la salida estandard.
Arreglos bidimensionales
formato:
tipo nombre[longitud_1][longitud_2]
Ejemplo:
int digitos[2][10]
/* Programa: DIAGPRIN.C
Desc. : Suma la diagonal principal de una matriz*/
#include <stdio.h>
#define LON 2
int main(){
int i, j, suma, matriz[LON][LON];
return 0;
}
Ejercicio: Diaginv.c
Realice un programa que:
a) Pida 100 numero enteros y los almacene en una arreglo de 10 X 10
b) Sumar la diagonal principal inversa
c) Despliegue la suma
/* Programa: SUMAMAT.C
Desc. : Suma dos matrices dejando el resultado en una tercera*/
#include <stdio.h>
#define LON 2
int main(){
int i, j, a[LON][LON], b[LON][LON], c[LON][LON];
27
printf("\nEl resultado de la suma de A + B es:\n");
for (i=0; i < LON; i++) {
for (j=0; j < LON; j++)
printf("%2d ", c[i][j]);
putchar('\n');
}
return 0;
}
28
4
FUNCIONES
Tipos de variables: Parte 1
Alcance de variables
Las variables declaradas dentro de una función son privadas a esa función, ninguna
otra función puede tener acceso directo a ellas.
Variables automáticas
Cada variable local de una rutina comienza a existir cuando se llama a la función, y
desaparece cuando la función acaba.
Estas variables no conservan su valor entre dos llamadas sucesivas, y se les ha de
dar un valor en la entrada a la función.
Variables externas
Se definen fuera de las funciones; estas son externas a todas las funciones; esto es
variables globales a las que puede acceder cualquier función mediante su nombre.
A estas variables se les asigna memoria real.
Cuando son declaradas en otro archivo se debe usar la palabra reservada extern.
/*Programa : sqr.c
Descripción: Usa una función que recibe y regresa un valor entero*/
#include <stdio.h>
main() {
int n, c;
n = sqr(2);
printf("\nEl cuadrado de 2 es %d ", n);
}
Ejercicio: Eleva.c
Realice una funcion eleva(n, x) que eleve el valor de n a la potencia x y regrese el
numero elevado.
29
Funciones
Una función es una construcción que realiza una tarea. La cual incluye sentencias y
variables relacionadas, incluyendo los pasados como argumentos.
Una función puede ser compilada y almacenada en una librería o archivo, de
donde el encadenador la extrae.
Ejemplo:
void info(void) {
printf("\n%s\n%s\n%s\n",
"Tambien puede haber una funcion minima",
"por ej: void nada(void) { }",
"la cual no hace nada");
}
Forma general:
especificador_tipo nombre_funcion(declaración de argumentos ) {
cuerpo de la función
}
/* Programa: ABSOLUTO.C
Desc. : Devuelve el valor absoluto de un double */
#include <stdio.h>
float abs(float x) {
if (x >= 0.0)
return x;
else
return -x;
}
int main() {
float c;
scanf("%f", &c);
printf("%f", abs(c));
return 0;
}
Ejercicio: Par.c
Escriba una función par(n) que regrese un 0 si es par.
30
Ejercicio: Fact.c
Realice una función factorial(n) que regrese el factorial de n.
Nota:
No se puede usar goto para brincar de una función a otra. El código y los datos
definidos en cada función no pueden interactuar con código o datos definidos
dentro de otra función.
Las variables definidas dentro de una función son variables locales dinámicas.
(empiezan a existir cuando la función es llamada y se destruyen al terminar). Estas
variables no pueden guardar valor entre los llamados de las funciones.
/* Programa : LEELINEA.C*/
/* Descripcion: obtiene una linea en s, devuelve la longuitud*/
#include <stdio.h>
#define LIMITE 80
return(i);
}
int main() {
char linea[LIMITE];
int n;
n = lee_linea(linea, LIMITE);
while (n > 0) {
printf ("Numero de Caracteres %d ", n);
printf("%s\n", linea);
n = lee_linea(linea, LIMITE);
31
}
return 0;
}
Ejercicio: Ar_prom.c
Realice una función ar_prom(arreglo, tam) que reciba un arreglo de enteros, el
tamaño del mismo y que regrese el promedio de la suma de sus elementos.
Argumentos de funciones
Llamada por valor
Este método copia el valor del argumento dentro de los par metros formales de la
función y todos los cambios que sufran los parámetros no afectan el valor del
argumento usado para llamar la función.
Par metros formales de la función; son las declaraciones de las variables que
aceptan los valores de los argumentos.
/* Prog: Cambia.C
Desc: Usa una funcion que intercambia los valores de sus argumentos*/
#include <stdio.h>
paso = a;
a = b;
b = paso;
}
main() {
int x, y;
x = 10;
y = 20;
cambia(x, y);
printf("\nX = %d\nY = %d", x, y);
}
Ejercicio:
Diga cual es la salida del programa anterior.
Ejercicio: Marco.c
Realice una función marco('*', x1, y1, x2, y2) que dibuje un marco en pantalla.
donde '*' es el carácter con el que se dibujara el marco
x1 y y2 son las coordenadas de la esquina superior izquierda
x2 y y2 son las coordenadas de la esquina inferior derecha
32
Ejercicio: Str_busc.c
Escriba una función str_busca(str, c) que reciba una cadena de caracteres str, y un
carácter c. Busque el carácter en la cadena y regrese la posición en que se
encuentra el carácter en la cadena o un -1 si no se encuentra.
Archivos de encabezados
Muchas funciones en la librería estandard trabajan con tipos de datos específicos.
Estos tipos son definidos en archivos de encabezados los cuales vienen con el
compilador, y estos deben ser incluidos (usando #include) en los archivos donde se
haga referencia a una función de la librería estandard.
Estos archivos contienen todos los prototipos de las funciones relacionadas con el
archivo de encabezado.
Ademas contienen definiciones de constantes simbólicas como EOF y macros.
Nota:
El uso de las funciones mas comunes en los encabezados se irán tratando en el
transcurso del libro.
33
5
Apuntadores
Definición de apuntadores
Un apuntador es una variable que almacena una dirección de memoria.
Esta dirección es usualmente la localidad de otra variable en memoria.
Si una variable contiene la dirección de otra variable, entonces se dice que la
primera variable apunta a la segunda.
MEMORIA
Área libre
Código del programa que esta
en ejecución
D ire c c io n e s e n
m e m o ria 1500 1501 1510
V a ria b le s e n x
0 3
m e m o ria
n c
Nota:
Los apuntadores son también un tipo de variable, una computadora pequeña usa
normalmente dos bytes para un apuntador; algunos sistemas mas grandes usan
cuatro bytes.
Porque un apuntador es un tipo de datos único, necesitamos decirle al compilador:
1.- Crea una dirección para el apuntador.
2.- Crea una escala para el apuntador igual al
numero de bytes asociados con el tipo de dato al
que apunta.
3.- Marca esta variable como un apuntador.
34
Definiendo apuntadores
Ejemplo:
int *pn;
Inicial izando.
Ejemplo:
int n, *pn;
D ir e c c io n e s e n
m e m o r ia 1500 1501 1600 1601
V a r ia b le s e n * #
& \0
m e m o r ia
B a su ra B asura
n = 3;
pn = &n;
D ir e c c io n e s e n
m e m o r ia 1500 1501 1600 1601
V a r ia b le s e n 0 3 15 00
m e m o r ia
n *pn
La inicialización.
pn = &n
Se puede decir como: toma la dirección de la variable n y almacénala en la
dirección de pn.
Indireccion
Es el proceso de accesar el contenido de una variable a través de una variable
apuntador. Usando el operador *.
Ejemplo:
int n, *pn, x;
n = 3;
pn = &n;
x = *pn; ( x = 3)
35
El operador & solo se puede aplicar a variables y a elementos de un arreglo.
Construcciones como:
&(x+1)
&3
Son ilegales.
También es ilegal obtener la dirección de una variable register.
/*Programa...: ref.c
Descripcion: Intercambia dos numeros, ejemplo llamada por referencia
*/
#include <stdio.h>
int main(void) {
int x = 20, y = 10;
cambia(&x, &y);
printf("\nx = %d y = %d", x, y);
return 0;
}
paso = *x;
*x = *y;
*y = paso;
}
36
Ejercicio: Sqr2.c
Realice una funcion sqr(&n) que reciba una direccion a un numero entero, eleve el
numero al cuadrado y deje el resultado en el mismo numero.
/*Programa: LEEINT.C
Desc. : Funcion que lee un entero*/
#include <stdio.h>
#include <stdlib.h> /* atoi() */
gets(s);
*pi = atoi(s);
}
int main() {
int i;
puts("Numero: ");
leeint(&i);
printf("\n%d", i);
return 0;
}
Aritmética de apuntadores
En C se puede usar solo dos operaciones aritméticas sobre apuntadores:
+, -.
Ejemplo:
int *p, x = 1;
p = &x;
D ir e c c io n e s e n
m e m o r ia 1500 1501 1600 1601
V a ria b le s e n 0 1 15 00
m e m o r ia
x p
Si hacemos:
P++;
D ire c c io n e s e n
m e m o ria 1500 1501 1502 ... 1600 1601
V a r ia b le s e n 0 1 15 02
...
m e m o ria
x p
37
Cada vez que la computadora incrementa un apuntador, apuntara a la posición de
memoria del elemento siguiente en función de su tipo base.
También se puede sumar o restar entero a los apuntadores.
Apuntadores y arreglos
Los apuntadores y arreglos se utilizan casi de la misma manera para acceder a la
memoria. Sin embargo:
Un apuntador es una variable cuyos valores son direcciones.
El nombre de un arreglo es una constante que contiene la dirección del inicio del
arreglo también llamado apuntador fijo.
Cuando se declara un arreglo el compilador debe asignar una dirección base y la
cantidad de almacenamiento suficiente para alojar a todos los elementos del
arreglo.
Ejemplo:
int n[3] = {1, 2, 3}, *p;
D ire c c io n e s e n
m e m o ria 2000 2001 2002 2003 2004 2005
V a ria b le s e n 0 1 0 2 0 3
m e m o ria
n [0 ] n [1 ] n[2]
Las asignaciones:
p = n; y p = &n[0];
son equivalentes; y se asignara 2000 a p.
p = n + 1; y p = &n[1];
son equivalentes; y se asignara 2002 a p.
Nota:
Un apuntador es una variable, por lo que las operaciones como:
p = n; y p++;
son correctas.
Pero el nombre de un arreglo es una constante, no es una variable; así que
construcciones como:
n = p; o n++; o p = &n; o n += 2;
Son ilegales.
Nota:
Los arreglos y los apuntadores tienen una estrecha relación.
38
/* Programa....: REL.C
Descripcion.: Relaciones entre arreglos y apuntadores*/
#include <stdio.h>
int main() {
char c = 'A', *p, s[10];
p = &c;
printf("\n%c %c %c", *p, *p+1, *p+2); /* Se incrementa el contenido de donde apunta p */
s[0] = 'A';
s[1] = 'B';
s[2] = 'C';
s[3] = '\0';
p = s;
printf("\n%s %s %c %s", s, p, *(p+1), p+1);
return 0;
}
p=s
s = p - Invalido porque s no es una variable es una constante tipo apuntador
que apunta hacia s[0]
Ejercicio: Apordena.c
Realice una función ordena(arreglo, tam) que reciba un arreglo, su tamaño y
ordene el arreglo de menor a mayor.
Apuntadores a caracteres
Si se declara mensaje como:
char *mensaje;
La sentencia:
mensaje = "esta es una cadena"
/* Programa: LEESTR.C
Desc. : Funcion que lee un string de la entrada estandard */
#include <stdio.h>
main(){
char s[50];
leestr(s);
printf("%s", s);
}
/* Programa: STRLEN3.C
Desc. : Ejemplo de como puede estar implementada la funcion de la
biblioteca estandard strlen (usando apuntadores)*/
int strlen(char *s) {
int n;
for (n = 0; *s != '\0'; s++)
n++;
return n;
}
Ejercicio: Prnstr.c
Realice una función printstr(str) que reciba un apuntador a una cadena de
caracteres y la imprima en la salida estandard usando la función putchar y manejo
de apuntadores.
/* Programa: LEELIN2.C
Desc. : lee_linea (version con apuntadores)*/
#include<stdio.h>
lon = 0;
c = getchar();
while (lon < lim && c != EOF && c != '\n') {
*s = c;
lon++;
s++;
c = getchar();
}
*s = '\0';
return lon;
}
int main(void) {
char s[20];
40
int n;
printf("\nString: ");
n = lee_linea(s, 20);
printf("\n%s longitud = %d ", s, n);
return 0;
}
/* Programa: STRLEN4.C
DEsc. : Ejemplo de como puede estar implementada la funcion de la
biblioteca estandard strlen (implementada usando apuntadores)
Otra Version!*/
int strlen(char *s) {
char *p = s;
return p-s;
}
/* Programa: STRCPY2.c
Desc. : Copia origen a destino usando apuntadores */
#include <stdio.h>
main(){
char str1[80], str2[80];
Ejercicio: Strbusca.c
Escriba una función str_busca(str, c) que reciba un apuntador a una cadena de
caracteres str, y un carácter c. Busque el carácter en la cadena y regrese la posición
en que se encuentra el carácter en la cadena o un -1 si no se encuentra utilizando
apuntadores.
41
Ejercicio: Strcon.c
Realice una función concatena(str1, str2) que agregue la cadena de caracteres str2
al final de la cadena str1.
Ejercicio: reversa.c
Realice una función reversa(str) que reciba un apuntador a una cadena de
caracteres e invierta la cadena. Utilizando apuntadores.
Descripción
malloc aloja un bloc de memoria del tamaño de tam bytes.
malloc regresa un apuntador al bloc de memoria que ha alojado. Si no puede alojar
la cantidad de memoria requerida, regresa un NULL.
free()
#include <stdlib.h>
void free(void *ptr)
Desaloja memoria dinámica
Descripción
free desaloja un bloc de memoria dinámica que ha sido previamente alojado por
malloc. El Desalojo de memoria la libera para reusa miento.
ptr apunta al bloc de memoria a ser liberado.
/* Programa: NARREGLO.C
Desc. : Ingresa un arreglo de n elementos utilizando manejo de
memoria dinamica*/
#include <stdio.h>
#include <stdlib.h> /* malloc(), free() */
int main() {
int *lista, n, i;
Ejercicio: Apmenor.c
Realice un programa que:
a) Pida n números enteros y los almacene en un arreglo de n elementos
b) Busque el numero menor y el numero mayor
c) Despliegue el numero menor y el numero mayor
Ejercicio: Dinorden.c
Hacer un programa que:
a) Pida n números enteros y los almacene en un arreglo de n elementos
b) Los ordene de menor a mayor
c) Despliegue el arreglo
Arreglos de apuntadores
Los apuntadores son variables, as¡ que los podemos almacenar en un arreglo.
Declaración:
int *x[10];
Asignación:
x[2] = &v;
Encontrar el valor de v.
*x[2]
/* Programa: NOMBRES.C
Desc. : manejo de memoria dinamica, arreglo de apuntadores*/
#include <stdio.h>
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
#include <conio.h>
#define LIMITE 5
int main() {
char str[255], *nombre[LIMITE];
int i;
clrscr();
printf("\n\t\tIngresa una lista de nombres\n");
for (i=0; i < LIMITE; i++) {
printf("%2d.-Nombre ? ", i);
gets(str);
43
nombre[i] = (char *)malloc(strlen(str)+1); /* Asigna memoria a nombre*/
strcpy(nombre[i], str); /* Copia str a nombre */
}
printf("\n\t\tLista de nombres:\n");
for (i=0; i < LIMITE; i++)
printf("\n%2d.- %s", i, nombre[i]);
/* desaloja la memoria */
for (i=0; i < LIMITE; i++)
free(nombre[i]);
return 0;
}
Direccion Valor
Ejemplo:
float **n;
/* Programa: INDMULT.C
Desc. : Ejemplo de indireccion multiple */
#include <stdio.h>
int main() {
int x, *p, **q;
x = 10;
p = &x;
q = &p;
return 0;
}
44
/* Programa: NOMBRES2.C
Desc. : manejo de memoria dinamica, apuntadores a apuntadores*/
#include <stdio.h>
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
#include <conio.h>
int main() {
char str[255], **nombre;
int i, n;
clrscr();
printf("\n\t\tLista de nombres:\n");
for (i=0; i < n; i++)
printf("\n%2d.- %s", i, nombre[i]);
return 0;
}
45
Diferencias de arreglos bidimensionales y
arreglos de apuntadores
Ejemplo:
char cap[3][32] = { "introduccion",
"tipos, operadores y expresiones",
"control de flujo" /*No se pone coma*/
};
introduccio n\0
control de flujo\0
2 0 0 0 3 0 0 0 3 0 0 0 in t r o d u c c io n \ 0
2 0 0 1 3 0 0 1 3 0 0 1 t ip o s , o p e r a d o r e s y e x p r e s io n e s
2 0 0 2 3 0 0 2 3 0 0 2 c o n t r o l d e f lu jo \ 0
argc
Es el numero de argumentos en la linea de comandos del sistema operativo con
que se invoco el programa.
46
argv
Es un apuntador a un arreglo de cadenas de caracteres; que contienen los
argumentos. Cada cadena contiene un argumento.
Nota:
Es un arreglo de apuntadores. argc siempre será 1 porque el primer arg. es el
nombre del programa (algunos sist. op. incluyen el path).
Ejemplo:
1.- Hacer ejecutable el prog. llamado arg.exe por ejemplo.
2.- Correrlo: arg buenos días
/* Programa ARGS.C*/
#include <stdio.h>
#include <conio.h>
clrscr();
printf("\nNumero de Argumentos: %d", argc);
for (i = 0; i < argc; i++)
printf("\n%d.-%s", i, argv[i]);
return 0;
}
47
6
Estructuras
Definición
Una estructura es un conjunto de una o mas variables, posiblemente de tipos,
diferentes, agrupadas bajo un mismo nombre.
Las estructuras en C son equivalentes al record de Pascal.
struct
Palabra reservada para definir una estructura.
Ejemplo:
definición del tipo de estructura.
struct direc {
char nombre[30];
char calle[40];
char ciudad[20];
char estado[10];
unsigned long int zip;
};
Forma general:
struct etiqueta {
tipo nombre_variable;
tipo nombre_variable;
tipo nombre_variable;
.
.
tipo nombre_variable;
} variables_de_estructura;
48
Referenciando los elementos de la estructura:
nombre_estructura.nombre_elemento
Ejemplo:
dir.nombre
/* Programa: PERSONA.C
Desc. : Ejemplo de estructura.*/
#include <stdio.h>
#include <stdlib.h>
struct direc {
char nombre[30];
char dir[40];
unsigned int tel;
} direc_info;
printf("1. Ingresa\n");
printf("2. Consulta\n");
printf("3. Fin\n");
do {
printf("\nOpcion: ");
gets(s);
c = atoi(s);
} while (c < 0 || c > 3);
return c;
}
void agrega(void) {
char s[80];
printf("\nNombre : ");
gets(direc_info.nombre);
printf("Direccion: ");
gets(direc_info.dir);
printf("Telefono : ");
gets(s);
direc_info.tel = strtoul(s, '\0', 10);
}
void consulta(void) {
printf("%s\n", direc_info.nombre);
printf("%s\n", direc_info.dir);
printf("%u\n\n", direc_info.tel);
}
49
int main() {
char opcion;
for (;;) {
opcion = menu_op();
switch(opcion) {
case 1:
agrega();
break;
case 2:
consulta();
break;
case 3:
exit(0);
}
}
return 0;
}
Ejercicio: Alumno.c
Realice un programa alumnos.c que ingrese y consulte la siguiente estructura:
struct alumno {
char nombre[30];
int calif;
int sem;
};
Arreglo de estructuras
Para definir un arreglo de estructuras primero se define la estructura y después se
define el arreglo.
/* Programa: AGENDA.C
Desc. : Arreglo de estructura para simular una agenda*/
#include <stdio.h>
#include <stdlib.h>
struct direc {
char nombre[30];
char dir[40];
unsigned int tel;
} direc_info[MAX];
/* Inicializa la listaa */
void ini_lista(void) {
int i;
50
for (i = 0; i < MAX; ++i)
direc_info[i].nombre[0] = '\0';
}
return c;
}
return i;
}
i = busca_libre();
if (i == -1) {
printf("\nLista llena");
return;
}
printf("\nNombre : ");
gets(direc_info[i].nombre);
printf("Direccion: ");
gets(direc_info[i].dir);
printf("Telefono : ");
gets(s);
51
direc_info[i].tel = strtoul(s, '\0', 10);
}
int main() {
char opcion;
52
return 0;
}
Ejercicio: Aralumno.c
Adapte el programa agenda.c para que utilize la estructura alumno presentada en el
ejercicio anterior.
Nota:
Lo anterior significa que los cambios hechos al contenido de la estructura dentro de
la función no afectara a la estructura pasada como argumento.
/* Programa: PERSONA2.C
Desc. : Ejemplo de paso de estructuras a funciones*/
#include <stdio.h>
#include <stdlib.h>
struct direc {
char nombre[30];
char dir[40];
unsigned int tel;
};
printf("1. Ingresa\n");
printf("2. Consulta\n");
printf("3. Fin\n");
do {
printf("\nOpcion: ");
gets(s);
c = atoi(s);
} while (c < 0 || c > 3);
return c;
}
/* No podemos usar esta funcion ya que es paso por valor, en la funcion se crea una copia de la
estructura que le pasamos y actualiza la copia y no nuestra estructura original:
void agrega(struct direc dir_inf) {
char s[80];
printf("\nNombre : ");
gets(dir_inf.nombre);
53
printf("Direccion: ");
gets(dir_inf.dir);
printf("Telefono : ");
gets(s);
dir_inf.tel = strtoul(s, '\0', 10);
}*/
printf("%s\n", dir_inf.nombre);
printf("%s\n", dir_inf.dir);
printf("%u\n\n", dir_inf.tel);
}
int main() {
struct direc reg;
char opcion, s[80];
for (;;) {
opcion = menu_op();
switch(opcion) {
case 1: /* agregar: */
printf("\nNombre : "); gets(reg.nombre);
printf("Direccion: "); gets(reg.dir);
printf("Telefono : "); gets(s);
reg.tel = strtoul(s, '\0', 10);
break;
case 2:
consulta(reg);
break;
case 3:
exit(0);
}
}
return 0;
}
Ejercicio: Alumno2.c
Adapte el programa persona2.c para que utilize la estructura alumno presentada en
el ejercicio anterior.
54
Apuntadores a estructuras
C permite los apuntadores a estructuras igual que cualquier otro tipo de variable.
p = &persona;
Esto pone la dirección de la estructura persona en el apuntador p.
(*p).balance;
Los paréntesis son necesarios alrededor del apuntador porque el operador PUNTO
(.) tiene mayor prioridad mayor que el operador *.
/* Programa: PERSONA3.C
Desc. : Ejemplo de apuntadores a estructuras*/
#include <stdio.h>
#include <stdlib.h>
struct direc {
char nombre[30];
char dir[40];
unsigned int tel;
};
printf("1. Ingresa\n");
printf("2. Consulta\n");
printf("3. Fin\n");
do {
printf("\nOpcion: ");
gets(s);
c = atoi(s);
} while (c < 0 || c > 3);
return c;
}
printf("\nNombre : ");
gets(dir_inf->nombre);
printf("Direccion: ");
gets(dir_inf->dir);
printf("Telefono : ");
gets(s);
dir_inf->tel = strtoul(s, '\0', 10);
}
printf("%s\n", dir_inf->nombre);
printf("%s\n", dir_inf->dir);
printf("%u\n\n", dir_inf->tel);
}
int main() {
struct direc reg;
char opcion, s[80];
for (;;) {
opcion = menu_op();
switch(opcion) {
case 1:
agrega(®);
break;
case 2:
consulta(®);
break;
case 3:
exit(0);
}
56
}
return 0;
}
Ejercicio: Alumno3.c
Adapte el programa persona3.c para que utilize la estructura alumno presentada en
el ejercicio anterior.
57
7
Archivos
Entrada y salida
La entrada y salida se consigue mediante las funciones de la biblioteca estandard de
C. El archivo de encabezado que se necesita es el stdio.h.
Ejemplo:
#include <stdio.h>
Corrientes de Flujo
Corrientes y archivos
El sistema de E/S de C proporciona una interfaz independiente del dispositivo real
al que se accede; esto es, una abstracción entre el programador y el dispositivo que
se usa. Esta abstracción se llama corriente y el dispositivo real se llama archivo.
Corrientes
Almacenamiento temporal de archivo para transformar los dispositivos físicos en un
almacenamiento lógico. Esto permite que las corrientes sean independientes de los
dispositivos.
Existen dos tipos de corrientes: texto y binarias.
Corrientes de texto
Secuencia de caracteres organizadas en lineas terminadas por un carácter nueva
linea. La traducción del carácter nueva linea depende de la implementacion.
Corrientes binarias
Secuencia de bytes que tienen una correspondencia uno a uno con un dispositivo
externo.
Función fopen
FILE *fopen(const char *path, const char tipo);
Tipo: r w a r+ w+ a+ t b (agrega a un tipo en el modo indicado)
Regresa : un apuntador al archivo abierto si fue exitoso, o NULL si no.
Descripción:
La función fopen abre el archivo especificado por el path. El tipo de cadena de
caracteres especifica el tipo de acceso requerido para el archivo.
Esta cadena puede ser una de las siguientes: "r", "w", "a", "r+", "w+", "a+".
58
En adición a los valores listados arriba, ademas una "t" o una "b" puede ser
agregada al tipo o insertado antes del carácter + para especificar el modo de
traducción para la nueva linea. La "t" especifica el modo texto y la "b" especifica el
modo binario.
Función fclose
Prototipo: int fclose(FILE *stream);
int fcloseall(void);
Regresa: (fclose) 0 si es exitoso, o EOF si no.
(fcloseall) el numero total de flujos cerrados si es exitoso,
o EOF si no.
Descripción:
La función fclose cierra la corriente dada. La función fcloseall cierra todas las
corrientes abiertas excepto stdin, stdout, stderr (y en MS-DOS, stdaux, y stdprn).
Función getc(corriente)
prototipo: int getc(stream)
FILE *stream
Regresa el siguiente carácter de la corriente de entrada de la posición actual e
incrementa el indicador de la posición del archivo.
/* Programa : desp.c
Descripcion: lee una archivo ASCII y lo despliega en la pantalla*/
#include <stdio.h>
#include <stdlib.h>
if (argc != 2) {
puts("Uso: desp <nombre_archivo> ");
exit(1);
}
/* Programa : typ.c
Descripcion: Despliega un archivo de texto dado en la linea de
comandos, en la pantalla dividiendolo en paginas,
presenta el # de pagina y hace una pausa entre cada pagina.*/
#define PANT 23
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void titulos(char *s, int n, char *nom_prog) {
sprintf(s, " Archivo: %s %s %3d", nom_prog,
" Pagina: ", n);
}
int main(int argc, char *argv[]) {
int c, opl=PANT, ln=0, pag=1;
char s[80];
FILE *archivo;
if (argc == 1) {
printf("\n uso: typ archivo.extension \n");
exit(1);
}
archivo = fopen(argv[1], "r");
titulos(s, pag, argv[1]);
printf("%s\n", s);
while ((c=fgetc(archivo)) != EOF) {
fputc(c, stdout); /*Escribe al archivo estandard de salida */
if (c == '\n')
ln++;
if (ln == opl) {
ln=0;
pag++;
60
titulos(s, pag, argv[1]);
printf("Presione ENTER para continuar");
getchar();
printf("\n%s\n", s);
}
}
return 0;
}
Ejercicio: Typeprn.c
Adaptar typ.c para que la salida sea asia la impresora.
Función putc(corriente)
Prototipo: int putc(int c, FILE *fp);
/* Programa : Aminus.c
Descripcion: Pasa un archivo con letras mayusculas a otro con minusculas*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void) {
FILE *f, *d;
char c;
f = abre_arch("inslist.pas", "r");
d = abre_arch("inslist2.pas", "w");
61
Ejercicio: Mayminus.c
Modificar aminus.c para que el archivo de entrada y el de salida lo tome de la linea
de comandos.
Ejercicio: Conviert.c
Adaptar el programa anterior para que convierta de minúsculas a mayúsculas o
viceversa según una opción dada en la linea de comandos.
Función ferror
Incluye : <stdio.h>
Prototipo: int ferror(FILE *stream);
Regresa : un valor no cero para indicar un error en el flujo, o 0 para indicar que
no hubo error.
La rutina ferror evalúa un error en el flujo para lectura o escritura. Si un error ha
ocurrido, el indicador de error para el flujo permanece fijo hasta que el flujo es
cerrado o retrocedido, o hasta que clearerr es llamada contra este (error).
/* Programa : Copia.c
Descripcion: Copia un archivo a otro archivo*/
#include <stdio.h>
#include <stdlib.h>
return 0;
}
/* Programa....: DelTab.c
Descripcion.: El programa sustituye espacios por tabs en el texto
del archivo y hace un chequeo de errores.
Autor.......: R. Cesar Rodriguez C.
Fecha.......: Junio/93*/
#include <stdio.h>
#include <stdlib.h>
#define TAB_SIZE 8
#define IN 0
#define OUT 1
void error(int e) {
if (e == IN)
puts("Error en la entrada");
else
puts("Error en la salida");
exit(1);
}
if (argc != 3) {
puts("Uso: deltab <archivo_fuente> <archivo_destino>");
exit(1);
}
if ((in = fopen(argv[1], "rb")) == NULL) {
printf("No abrio archivo %s\n", argv[1]);
exit(1);
}
if ((out = fopen(argv[2], "wb")) == NULL) {
printf("No abrio archivo %s\n", argv[2]);
exit(1);
}
tab = 0;
do {
c = getc(in);
if (ferror(in))
error(IN);
63
if (c == '\t') {
for (i = tab; i < 8; i++) {
putc(' ', out);
if (ferror(out))
error(OUT);
}
tab = 0;
}
else {
putc(c, out);
if (ferror(out))
error(OUT);
tab++;
if (tab == TAB_SIZE)
tab = 0;
if (c == '\n' || c == '\r')
tab = 0;
}
} while (!feof(in));
fclose(in);
fclose(out);
return 0;
}
Ejercicio: Sinesp.c
Escriba un programa que reciba un archivo de texto, elimine todos los espacios al
inicio de cada linea y lo deje en otro archivo de texto.
Ejercicio: Concat.c
Escriba un programa que reciba dos archivo de texto, y concatene el primero al
final del segundo archivo.
Función fwrite
Incluye : <stdio.h>
Prototipo: size_t fwrite(const void *buffer, size_t size, size_t count,
Regresa : el numero de campos completos escritos actualmente.
Descripción
La función fwrite escribe hasta el tamaño de la longitud total de campos desde el
buffer a la corriente de output.
El apuntador al archivo asociado con la corriente es incrementado por el numero de
bytes actualmente escritos.
Si el flujo es abierto en modo texto, cada retorno de carro es remplazado con un
par de carriage-return-line-feed. El remplazo no tiene afecto sobre el valor de
regreso.
64
/* Programa....: AGENDA2.C
Descripcion.: Graba un arreglo de estructuras a disco/lo recupera
Autor.......: R. Cesar Rodriguez C.
Fecha.......: Junio/93*/
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#define SIZE 50
struct archivo {
char nombre[20],
direc[40];
int cuartos;
int pisos;
float renta;
} reg[SIZE];
/* Inicializa la lista. */
void ini_reg(void) {
register int i;
if (i == SIZE) {
puts("Lista Llena");
return;
}
printf("Nombre : ");
gets(reg[i].nombre);
printf("direccion : ");
gets(reg[i].direc);
printf("Numero de cuartos: ");
gets(s);
reg[i].cuartos = atoi(s);
printf("Numero de Pisos : ");
gets(s);
65
reg[i].pisos = atoi(s);
printf("Precio de Renta : ");
gets(s);
reg[i].renta = atof(s);
}
/* Despliega la lista */
void despliega(void) {
register int i;
if (fwrite(®[i],sizeof(struct archivo),1,fp) != 1)
puts("Error de escritura en el archivo");
}
66
if (feof(fp))
return;
puts("Error de lectura en el archivo");
}
}
do {
printf(" M E N U\n");
printf("A)ltas\n");
printf("D)espliega\n");
printf("F)in\n");
printf("Opcion: ");
gets(s);
} while (!strchr("adf", tolower(*s)));
return tolower(*s);
}
int main(void) {
char opcion;
ini_reg();
carga(); /* carga archivo a una lista de estructuras */
for (; ;) {
opcion = menu();
switch(opcion) {
case 'a':
altas();
break;
case 'd':
despliega();
break;
case 'f':
registra();
exit(0);
}
}
return 0;
}
Ejercicio: Stalumno.c
Adapte el programa agenda2.c para que utilice la estructura alumno de los
ejercicios planteados en el capitulo de estructuras.
67
8
Tema avanzados
Tipos de variables: Parte 2
Variables static
Pueden ser internas o externas. Las variables static internas son locales a una
función pero a diferencia de las automáticas, su existencia es permanente.
Proporcionan un medio de almacenamiento permanente y privado en una función.
Una variable static externa es accesible en el resto del archivo fuente donde fue
declarada, pero no en otro.
Ejemplo:
static int i;
static char c;
Nota:
Excepto cuando la variable es declarada static.
Esto causa que el compilador trate a la variable como si fuera una variable global
para propósito de almacenamiento. Pero con el limite de alcance solo dentro de la
función.
Variables registro
Una declaración register avisa al compilador que la variable en cuestión será muy
usada. Cuando es posible, las variables register se colocan en los registros de la
maquina, lo que producirá programas mas cortos y
rápidos.
Ejemplo:
register int x;
register char c;
68
Operadores: Parte 2
Operador coma ,
Una pareja de expresiones separadas por una coma se evalúa de izquierda
a derecha, y el tipo del resultado es el mismo que el operando derecho.
Ejemplo:
reverse(char s[]) { /* invierte la cadena s */
int c, i, j;
Nota:
Las comas que separan argumentos en las funciones o variables en las
declaraciones, etc., no son operadores ni garantizan que la evaluación se realice de
izquierda a derecha.
Nota:
Dependen explícitamente de la maquina.
Operador complemento ~
Invierte la representación de la cadena de bits de su argumento, los ceros se
convierten en unos, y los unos en ceros.
Ejemplo:
int x;
Si:
x = 6; => 00110
~x = 25; => 11001
X Y X & Y X ^ Y X | Y
0 0 0 0 0
0 1 0 1
1
1 0 0 1 1
1 1 1 0 1
x = 1; --------> 0001
y = 2; --------> 0010
----
b = x & y; -----> 0000 => b = 0
Ejemplo: | (OR)
unsigned int x, y, b;
x = 1; --------> 0001
y = 1; --------> 0001
----
b = x | y; -----> 0001 => b=1
70
x = 1; --------> 0001
y = 2; --------> 0010
----
b = x | y; -----> 0011 => b = 3
x = 2; --------> 0010
y = 3; --------> 0011
----
b = x | y; -----> 0011 => b = 3
x = 1; --------> 0001
y = 2; --------> 0010
----
b = x ^ y; -----> 0011 => b = 3
x = 2; --------> 0010
y = 3; --------> 0011
----
b = x ^ y; -----> 0001 => b = 1
/* Programa....: DESPIZQ.C
Descripcion.: Desplazamiento de bits a la izquierda
Autor.......: R. Cesar Rodriguez C.
Fecha.......:
Modificacion: Junio/93
*/
#include <stdio.h>
int main(void) {
int a, b;
/* a = 00001101
<< 2 = 00110100
---------- */
a = 13; /* 1001 */
a = a << 2; /* 1010 */
printf(" a = %d ", a ); /* 1011 */
/* 1100 */
return 0;
}
71
/* Programa....: DESPDER.C
Descripcion.: Desplazamiento de bits a la derecha
Autor.......: R. Cesar Rodriguez C.
Fecha.......: Junio/93
Modificacion:
*/
#include <stdio.h>
int main(void) {
int a, b;
/* a = 00001101
>> 1 = 1
---------- */
a = 13; /* 1001 */
a = a >> 1; /* 1010 */
printf(" a = %d ", a ); /* 1011 */
/* 1100 */
return 0;
}
/* Programa....: ANDBITS.C
Descripcion.: AND bits
Autor.......: R. Cesar Rodriguez C.
Fecha.......: Junio/93
Modificacion:
*/
#include <stdio.h>
int main(void) {
int a, b;
/* a = 00000011
& 01 = 0001
---------- */
a = 3;
a = a & 01;
printf(" a = %d ", a );
return 0;
}
72
/* Programa....: BITCOUNT.C
Descripcion.: cuenta los bits 1 en n
Autor.......: R. Cesar Rodriguez C.
Fecha.......: Junio/93
Modificacion:
*/
#include <stdio.h>
int main(void) {
int a, b;
/* a = 00110100
= 43210
---------- */
a = 52;
printf(" bitcount(a) = %d ",bitcount(a));
return 0;
}
for ( b = 0; n != 0; n >>= 1 )
if ( n & 01 )
b++;
return b;
}
/* Programa....: LEEBITS.C
Descripcion.: toma n bits a partir de la posicion p*/
#include <stdio.h>
int main(void) {
int a, b;
a = 52;
printf(" getbits(x, 4, 2) = %d ", getbits(a, 4, 2));
return 0;
}
Definicion de tipos
Uniones
Una unión es una localidad de memoria la cual es usada por dos o mas
variables diferentes; generalmente de tipos diferentes.
Forma general:
unión etiqueta {
tipo nombre_de_variable;
.
tipo nombre_de_variable;
} variable_union;
Ejemplo:
union int_char {
int i;
char c;
};
Byte 0 Byte 1
/* Programa: UNION.C */
#include <stdio.h>
union pw {
int i;
char s[2];
};
74
Enumeraciones
Es una extensión al lenguaje C agregado por el ANSI C.
Una enumeración es un conjunto de nombres de constantes enteras las cuales
especifican todos los valores legales que debe tener un tipo de variable.
Forma General:
enum nombre {lista de enumeración} lista_variables;
/* Programa: ENUM.C */
#include <stdio.h>
#include <conio.h>
enum numeros {
cero,
uno,
dos,
cinco = 5,
seis
} numero;
int main(void) {
clrscr();
printf("\n%d\n%d\n%d\n%d", uno, dos, cinco, seis);
return 0;
}
Typedef
Permite re definir nuevos nombres de datos.
Forma general:
typdef nombre_tipo;
Ejemplo:
typedef float flotante;
flotante i;
typedef struct registro {
int clave;
char nombre[40];
float calif;
};
registro reg;
reg.clave = 10;
75
Recursion
Una función es recursiva si una sentencia en el cuerpo de la función se llama a si
misma.
/*Programa: FACTREC.C
Desc. : Usa una funcion normal y na recursiva para sacar el factorial*/
#include <stdio.h>
int fact(int n) { /* no recursiva */
int i, f = 1;
return(f);
}
int factr(int n) { /* Funcion recursiva */
if (n == 0)
return 1;
else
return(n*fact(n-1));
}
int main() {
int n;
return 0;
}
Ejemplo
Impresión de un numero en forma de cadena de caracteres.
Los dígitos se generan en orden inverso: los de menor peso se encuentran
disponibles antes que los de orden superior, pero deben imprimirse después.
Solución 1
Consiste en almacenar los dígitos en un arreglo según se van generando.
/* Programa: PRINTD.C
Desc. : Convierte un entero a un string*/
#include <stdio.h>
void printd(int n) { /* imprime n en decimal */
char s[10];
int i;
if (n < 0) {
76
putchar('-');
n = -n;
}
i = 0;
do {
s[i++] = n % 10 + '0'; /* toma el siguiente caracter */
} while(( n /= 10) > 0); /* lo descarta */
return 0;
}
Solución 2
Usando una función recursiva, en la que cada llamada a printd primero se llama a si
misma para hacer frente a los dígitos delanteros y a continuación imprime el ultimo.
/* Programa: tprintd2.c */
#include <stdio.h>
void printd(int n);
int main(void) {
int n;
return 0;
}
if (n < 0) {
putchar('-');
77
n = -n;
}
if (( i = n / 10) != 0)
printd( i );
putchar(n % 10 + '0');
}
Ejercicio C3.3.
Escribe una versión recursiva de la rutina reversa, que invierte una cadena.
78
Bibliografia
1. El lenguaje de programacion C, Segunda edicion
Brian W. Kernighan
Dennis M. Ritchie
Prentice Hall.
2. El lenguaje de programacion C
Brian W. Kernighan
Dennis M. Ritchie
Prentice Hall.
3. C the complete reference, second edition
Herbert Schildt
Osborne McGraw Hill
79