Introducción
EL lenguaje C es el
resultado de un proceso de desarrollo que inició con un lenguaje denominado
BCPL. Este influenció a otro llamado B (inventado por Ken Thompson). En los
años 70; este lenguaje llevó a la aparición del C. Con la popularidad de las
micro computadoras muchas compañías comenzaron a implementar su propio C por lo
cual surgieron discrepancias entre si. Por esta razón ANSI (American National
Standars Institute, por sus siglas en inglés), estableció un comité en 1983
para crear una definición no ambigua del lenguaje C e independiente de la
máquina que pudiera utilizarse en todos los tipos de C. Algunos de las C
existentes son: Quick C , C++ , Turbo C, Turbo C ++ , Borland C Borland C++,
Microsoft C
C es un lenguaje de
programación de nivel medio ya que combina los elementos del lenguaje de alto
nivel con la funcionalidad del ensamblador. Su característica principal es ser
portátil, es decir, es posible adaptar los programas escritos para un tipo de
computadora en otra. Otra de sus características principales es el ser
estructurado, es decir, el programa se divide en módulos (funciones)
independientes entre sí.
El lenguaje C
inicialmente fue creado para la programación de: Sistemas operativos,
Intérpretes, Editores, Ensambladores, Compiladores, Administradores de bases de
datos. Actualmente, debido a sus características, puede ser utilizado para todo
tipo de programas.
ELEMENTOS
GENERALES DE UN PROGRAMA EN C
Aunque cada uno de los
programas son distintos, todos tienen características comunes. Los elementos de
un programa en C son los siguientes:
Comentarios
Inclusión de archivos
main()
{
variables locales
flujo de sentencias
}
Definición de
funciones creadas por el programador utilizadas en main()
Comentarios: Se identifican porque
van entre diagonales y asterisco. Nos sirve para escribir información del
programa pero que no forme parte de él. Por ejemplo especificar que hace el
programa, quien lo elaboró, en que fecha, que versión es, etc.
Inclusión de archivos: Consiste en mandar
llama- r a la o las bibliotecas
donde se encuentran definidas las funciones de C (instrucciones) que estamos
utilizando en el programa. En realidad, la inclusión de archivos no forma parte
de la estructura propia de un programa sino que pertenece al desarrollo
integrado de C. Se incluye aquí para que no se olvide que debe mandar llamar a
los archivos donde se encuentran definidas las funciones estándar que va a
utilizar.
main(): En C todo esta constituido a base de
funciones. El programa principal no es la excepción. main() indica el comienzo
de la función principal del programa la cual se delimita con llaves.
Variables locales: Antes de realizar
alguna operación en el programa, se deben declarar la(s) variable(s) que se
utilizarán en el programa.
Flujo de sentencias: Es la declaración de
todas las instrucciones que conforman el programa.
Definición de funciones creadas por el
programador utilizadas en main(): Finalmente, se procede a definir el contenido
de las funciones utilizadas dentro de main(). Estas contienen los mismos
elementos que la función principal.
Después de cada
asignación o función es imprescindible colocar un punto y coma (;) ya que éste
termina las proposiciones.
En C, los comandos
deben ser escritos con letras minúsculas. En el caso de las variables o la
funciones definidas por el usuario la situación es similar: no es lo mismo Apellido
que apellido que
APELLIDO, el compilador de C, los toma como tres nombres distintos. Por
tanto, asegúrese de mandar llamar las variables o funciones exactamente de la
misma forma en que las declaró.
Los tipos de datos son
identificadores que usa cada lenguaje para saber la clase de información que va
a tomar una variable. Por ejemplo: si quiero utilizar la variable
"cantidad" para almacenar un número entero, declararé
"cantidad" como una variable de tipo int lo que significa sólo
aceptará valores de tipo entero.
Los tipos de datos
básicos que maneja C son:
·
char
identifica el contenido de la variable que se declare como caracter. Su
longitud es de 1 byte.
·
int
se refiere a valores de tipo entero. Ocupa 2 bytes.
·
float
indica que la variable recibe datos de tipo real con aproximadamente 6 digitos
de precisión. Su longitud en bytes es de 4.
·
double
define variables que aceptan datos de tipo real con 12dígitos de precisión.
Cada variable ocupa 8 bytes de memoria.
·
void
Este tipo de dato sirve para declarar funciones que no devuelven valores. Su
cantidad de bytes es cero.
Además de los
anteriores, podemos crear otros tipos de datos al combinarlos con modificadores
de tipo como signed, unsigned, long y short.
También existen los
modificadores de acceso que sirven para controlar las formas en que se acceden
o se modifican las variables. Estos modificadores son const y volatile.
Una variable de tipo const trabaja como una constante, ya
que recibe sus valores por una inicialización explícita, o bien por algún medio
dependiente del hardware. Por ejemplo: const int x; crea la variable entera x
que no puede ser modificada por el programa pero si inicializada.
El modificador volatile se usa para indicar al
compilador que el valor de una variable se puede cambiar por medios externos
(no especificados) al programa. Por ejemplo la dirección de una variable global
puede ser pasada a la rutina del reloj del sistema operativo y usada para
mantener el tiempo real del sistema. En este caso, el contenido de la variable
es cambiado sin que haya una sentencia que así lo indique.
Es importante que
respetemos estos tipos de modificadores ya que ayudan a la optimización de las
funciones del compilador. Se pueden usar ambos modificadores juntos.
DECLARACION DE VARIABLES
Forma general:
Tipo_de_dato Variable;
Donde tipo_de_dato
puede ser cualquiera que esté permitido en C y Variable una palabra que
designemos para recibir datos.
No hay cantidad máxima
de caracteres (letras o palabras) que podamos utilizar para crear variables
pero si hay dos que tengan los primeros 6 caracteres significativos iguales, C
las tomará como si fuesen la misma.
Tampoco podemos
utilizar como variables aquellos términos que ya han sido definidos previamente
por el propio C o por el usuario como variables de otro tipo.
Las variables de tipo cadena
se declaran como un conjunto de caracteres. Por ejemplo:
char nombre[30];
Donde 30 es el número
de caracteres máximo que puede tener la cadena.
De acuerdo al lugar
donde se declaran, las variables pueden ser globales, formales o locales.
Variables
locales: Son aquellas que se declaran dentro de un
conjunto de código relacionado lógicamente entre si (sentencias de control o
funciones) Por ejemplo:
|
funcion_A() { int x; . . . } |
funcion_b() { int x; . . . } |
En las funciones anteriores,
declaramos dos variables llamadas "x" con el mismo tipo. Si se trata
de utilizar alguna de las variables fuera de las funciones a las que
pertenecen, se marcará un error porque el tipo sólo ha sido definido para
utilizarse dentro de las llaves donde fue declarada. El que ambas variables se
llamen "x" no quiere decir que sean la misma o que ocupen el mismo
lugar en la memoria dado que las variables locales se crean y se destruyen cada
vez que se sale del bloque en el que son declaradas por tanto, también su
contenido se pierde al salir del él.
Parámetros formales: Muchas de las
funciones necesitan argumentos. Los argumentos son datos que recibe la función
desde el exterior. A las variables en que sirven para transmitir estos datos se
les llama parámetros formales de la función. Su comportamiento es el mismo al
de cualquier otra variable local. Veamos el siguiente ejemplo:
/*Devuelve la suma de
dos números dados */
suma(int a, int b)
{
a+=b; /* a toma el valor de a+b */
return(a);
}
Esta función realiza
la suma de dos números. Utiliza dos parámetros formales: a y b los cuales deben
ser declarados en la llamada a suma() para luego poder utilizarlas dentro de la
función como variables locales. También se destruyen al salir de la función.
Se debe tener mucho
cuidado de que los parámetros formales que se declaran sean del mismo tipo que
los valores que se introducen cuando se manda llamar la función porque podría
obtener resultados inesperados.
Variables globales: Este tipo de variables
se conocen a través de todo el programa por lo cual se pueden usar en cualquier
parte de la ejecución de éste. Se declararan antes de utilizar la variable por
primera vez. Se recomienda que sea al principio del programa para mantener un
orden.
Sentencias de asignación
La forma general de
asignar valores a una variable es:
nombre_variable=expresión
Expresión puede ser
desde una constante hasta una combinación de variables, operadores y
constantes.
Si se mezclaran
variables de un tipo con las de otro, se aplica la regla de conversión de tipos
que consiste en que el valor del lado derecho de la asignación se convierte al
tipo de dato de la variable del lado izquierdo (que es la que va a
recibir el dato) siempre y cuando ésta última tenga mayor longitud en
bytes. Por ejemplo, una variable int podemos asignarla a otra variable de tipo
float pero no viceversa.
Un arreglo es un
conjunto de elementos del mismo tipo agrupados en una sola variable. También se
les conoce con el nombre de arreglos.
Para ingresar a un
elemento en particular, utilizamos un índice. Existen arreglos
unidimensionales, bidimensionales y multidimensionales.
Su uso más común es en
la implementación de cadenas de caracteres. en C no existen variables de tipo
cadena por lo cual se utiliza un arreglo de caracteres.
Físicamente, un
arreglo es un conjunto de localidades de memoria contiguas donde la dirección
más baja corresponde al primer elemento y la dirección más alta al último.
En un arreglo de n
elementos, éstos ocuparan desde la casilla 0 hasta la n-1.
Por si mismo, el
nombre del arreglo apunta a la dirección del primer elemento del arreglo.
La forma general para
definir un arreglo unidimensional es
la siguiente:
tipo_de_dato
nombre_variable[tamaño]
tipo_de_dato se refiere al tipo de dato de
cada elemento del arreglo y tamaño es la cantidad de elementos agrupados en la
misma variable.
Para acceder a uno de
los elementos del arreglo en particular, basta con invocar el nombre del
arreglo y especificar entre corchetes el número de casilla que ocupa el
elemento en el arreglo. Por ejemplo, si queremos acceder al cuarto elemento de
un arreglo de 10, se invocaría de la siguiente manera:
nombre_variable[3]
La forma de pasar un
arreglo a una función consiste en llamar a la función y en el argumento,
especificar el nombre del arreglo sin ninguna indexación. Esto hace que se pase
a la función la dirección del primer elemento del arreglo ya que en C no es
posible pasar el arreglo completo como argumento. Por ejemplo:
main()
{
int conjunto[20];
clrscr();
.
.
funcion(conjunto);
.
.
}
Aquí, al pasar el arreglo
conjunto a función, estamos pasando la dirección en memoria del primer elemento
de conjunto. En caso de que dentro de la función tuviésemos que acceder a algún
elemento del arreglo, se pasa de la misma manera sólo que dentro de la función
utilizaremos los corchetes para acceder al elemento deseado.
Hay tres formas de
declarar un arreglo como parámetro formal: como un arreglo delimi-tado, como un
arreglo no delimitado y como un puntero.
Por ejemplo:
funcion1(int
conjunto[20]) /*Delimitando el array*/
{
.
.
.
}
o como
funcion1(int
conjunto[]) /*arreglo no delimitado*/
{
.
.
.
}
o se puede declara
como
funcion1(int
*conjunto) /*como un puntero*/
{
.
.
.
}
El resultado de los
tres métodos de declaración es idéntico.
Definimos una cadena
en C como un arreglo de caracteres que al final tiene un caracter nulo ('\0').
Por esta razón es necesario que al declarar los arreglos estos sean de un
caracter más que la cadena más larga que pueda contener.
Por ejemplo si se
desea crear un cadena que contenga 5 caracteres la declaración debe hacerse
como sigue:
char cadena[6];
Esto es con el fin de
dejar el último espacio para el caracter nulo.
No es necesario añadir
explícitamente el caracter nulo de las constantes de cadena porque el
compilador de C lo hace automáticamente.
Un arreglo bidimensional es un arreglo de arreglos
unidimensionales. Constituyen la forma m s simple de los arreglos
multidimensionales.
Su forma general de
declaración es
tipo_dato
variable[primer índice][segundo índice];
El primer índice
corresponde a la filas y el segundo a las columnas.
Cuando se utiliza un
arreglo bidimensional como argumento de una función, realmente se pasa sólo la
dirección del primer elemento (el[0][0]). Sin embargo, la función que recibe un
arreglo bidimensional como parámetro tiene que definir al menos la longitud de
la segunda dimensión. Esto es necesario debido a que el compilador de C
necesita "conocer" la longitud de cada fila para ordenar el arreglo
correctamente. Por ejemplo, una función que recibe un arreglo bidimensional de
5,9 se declara así:
funcion(int
matriz[][9])
{
.
.
.
}
No es necesario
especificar la primera dimensión pero la segunda si ya que el compilador de C
la necesita para saber donde empieza la segunda fila.
También podemos
utilizar arreglos bidimensionales para crear arreglos de cadenas. El primer
índice indicaría el número de cadenas y el segundo la longitud máxima de las
cadenas.
char mensajes[5][20];
En la declaración
anterior se especifica que tenemos un arreglo llamado mensajes el cual contiene
5 cadenas de 20 caracteres cada una.
Para acceder a una
cadena en especial, sólo especificamos el número de cadena (de 0 al número de
cadenas menos 1). Ejemplo:
printf("%s",mensajes[3]);
Aquí mandamos imprimir
la cadena número 3 de la variable mensajes. Esto sera equivalente a
printf("%s",mensajes[3][0]);
aunque es más común
utilizar la primera forma.
En C, podemos también
se puede crear arreglos más de dos dimensiones el límite de dimensiones, viene
dado por el compilador. Su forma general de declaración es
tipo_dato variable
[longind1][longindice2] ...[longindiceN]
donde tipo_dato es el
tipo de dato de los elementos del arreglo y longind1, longind2...longindN es la
longitud de cada dimensión del arreglo. Este tipo de arreglos no se utiliza muy
frecuentemente debido a el gran espacio en memoria que ocupan. Otra desventaja
es que el acceso a un arreglo multidimensional dura más tiempo que el requerido
por uno del tipo unidimensional.
Cuando se pasan arreglos
multidimensionales a funciones, se tiene que declarar todo excepto la primera
dimensión. Por ejemplo:
funcion1(int
multiarreglo[][3][[4][5])
{
.
.
.
}
main()
{
int
m[2][3][4][5];
funcion(m[][3][4][5]);
.
.
.
}
Claro que si se desea,
se puede especificar también la longitud de la primera dimensión.
En C, podemos
inicializar arreglos globales y arreglos estáticos locales en el momento de
declararlos. No es posible inicializar arreglos globales no estáticos.
Su forma general de
inicialización es
tipo_dato variable
[tamaño 1] [tamaño2] ... [tamaño] = {lista de valores};
Lista de valores es un
conjunto de constantes, separadas comas, cuyo tipo es compatible con tipo_dato.
La primera constante se coloca en la primera posición del arreglo, la segunda
constante en la segunda posición, y asi sucesivamente.
int
digitos[5]={'0','1','2','3','4',};
En el caso de los
arreglos unidimensionales de caracteres podemos inicializarlos abreviadamente
con la forma:
char variable [tamaño]="cadena";
Por ejemplo:
char
nombre[6]="clase";
Lo anterior es lo
mismo que si inicializaramos nombre caracter a caracter como en el ejemplo de
dígitos.
char
nombre[6]={'c','l','a','s','e','\0'};
PUNTEROS
Un puntero es una zona
de la memoria que contiene la dirección de otra zona de memoria.
En C, es muy
importante el manejo de los punteros para una fructífera programación. Sus
principales ventajas son:
·
Los punteros proporcionan los medios por los
cuales las funciones pueden modificar sus argumentos de llamada.
·
Los punteros se utilizan para soportar las
rutinas de asignación dinámica de C.
·
El uso de punteros puede mejorar la eficiencia
de ciertas rutinas.
Aunque también cuenta
con desventajas como
·
Son un recurso peligroso ya que los no
inicializados o punteros descontrolados pueden provocar el fallo del sistema.
·
Es fácil utilizar punteros de forma incorrecta y
ésto causa fallas muy difíciles de encontrar.
Los punteros pueden
ser de cualquier tipo de datos. Esto quiere decir que puede haber punteros que
contengan la dirección de variables de cualquier tipo.
La forma general de
declarar una variable de este tipo es:
tipo_dato
*nombre_variable;
tipo_dato es cualquier
tipo de dato que soporte el C y nombre_variable es el nombre de la variable
puntero. El * es el indicador de que nos estamos refiriendo a un puntero.
Existen dos operadores
monarios (sólo necesitan un operando) utilizados para la manipulación de
punteros. Ellos son el "&" y el asterisco "*".
Cuando una variable
puntero va precedida del &, nos referimos a su dirección en memoria.
Por ejemplo:
Suponga que la
variable dato ocupa la celda de memoria número 1000 y contiene una 'A'.
s=&dato; la dirección de dato que es 1000.
La dirección no tiene
nada que ver con el valor de dato. el operador "&" devuelve la
dirección de la variable que le sigue.
El otro operador es el
"*". Cuando éste precede a una variable puntero indica el valor de la
variable puntero.
Por ejemplo:
s=*dato; Aquí s
contendrá 'A' porque es el valor que se encuentra almacenado en dato.
Debe asegurarse de que
las variables puntero apunten siempre al tipo de dato correcto es decir, que
una variable puntero tipo int sea asignada a otra variable puntero del mismo
tipo y así respectivamente. De lo contrario, aunque no se produzcan errores al
compilarlo (sólo advertencias) los resultados no serán los deseados.
Existe una estrecha
relación entre los punteros y los arrays ya que un array por si mismo es un
puntero a la dirección de su primer elemento (Un nombre de array sin índice
devuelve la dirección de comienzo del array que es el primer elemento). Por
tanto, podemos intercambiar información entre punteros y arrays del mismo tipo
de dato. ejemplo:
char cad[30], punt;
char *punt;
punt=cad;
Arriba, tenemos un
array de 30 caracteres y un puntero a caracter así que al asignar cad a punt,
almacenamos en punt la dirección del primer elemento de cad.
Para acceder al quinto
elemento de cad lo podemos hacer de dos formas:
cad[4] ó *(punt+4)
Ambas formas nos dan
el mismo resultado.
Utilizamos el 4 para
acceder al quinto elemento porque los arrays comienzan en el elemento número 0.
C proporciona dos
métodos para acceder a los elementos de un array: la aritmética de punteros y
la ordenación de arrays. La elección de cual utilizar es importante ya que la
aritmética de punteros puede ser más rpápida que la indexación de arrays. En la
práctica es frecuente el uso de punteros para acceder a elementos de un array
en programas en C debido a que la velocidad es un factor importante en la
programación.
También podemos
agrupar punteros en arrays. Su formato de declaración sería el siguiente:
tipo_dato
*nombre_variable[tamaño];
Por ejemplo:
int *[20];
declara un array de 20
elementos de tipo puntero a entero.
Este tipo de arrays
poseen las mismas propiedades que los arrays comunes(en cuanto a la forma de
acceder a sus elementos) y se manejan de la misma forma que las variables
puntero simples (en cuanto a dirección y contenido). Por ejemplo, para asignar
la dirección de una variable entera llamada elem al octavo elemento del array
de punteros (que es una dirección), se indica
x[7]=&elem;
&elem significa
"la dirección de elem".
Para encontrar el valor
de elem desde el array se escribe
*x[7]
Para pasar un array de
punteros a una función podemos llamarla con el nombre del array sin índices.
Por ejemplo, la siguiente función utiliza un array de este tipo como parámetro:
despliega_elem(int *a[])
{
int i;
for(i=0;i10;i++)
printf("%d",*a[i]);
}
despliega_elem imprime
en pantalla el contenido de los elementos de a
Inicialización de
punteros
Después de declarar
una variable pero antes de asignarle un valor, contiene un valor desconocido.
Si se intenta utilizar el puntero antes dedar le un valor, probablemente
fallará no solo el programa, sino también el sistema operativo de la
computadora.
Es por esto que las
variables puntero también deben ser inicializadas.
Inicializar una
variable es darle un valor específico; ésto se realiza indirectamente, al
asignar la dirección de una variable a un puntero, o directamente, al declarar
un puntero nulo es decir, que no apunte a dirección alguna.
ejemplo:
main()
{
char car;
char*punt1,*punt2;
punt1=&car;
punt2=NULL;
.
.
.
}
Tenemos una variable
llamada car que es de tipo caracter, además punt1 y punt2 que son punteros a
caracter.
Al asignar la dirección
de car a punt1 (punt1=&car) estamos inicializando indi-rectamente a punt1
porque su nuevo contenido depende de la dirección que car ocupe en memoria
mientras que punt2 esta inicializado directamente ya que NULL es un valor
constante que le dimos. En este caso, NULL indica que ese puntero no apunta a
ninguna dirección (es como inicializar una variable entera en 0).
Se puede utilizar el
puntero nulo para hacer muchas de las rutinas de punteros más fáciles de codificar
y más eficientes. Por ejemplo, en la siguiente función, se leen los elementos
de un array hasta que se encuentre un puntero nulo.
lee( char *lista)
{
int n;
n=0;
while (lista!=NULL)
printf("%s",*lista[n]);
}
En este caso, NULL nos
sirve para determinar el fin de una lista de elementos.
ESTRUCTURAS
Las estructura es un
tipo de datos compuesto que permite el C. Se define como un conjunto de
variables relacionadas lógicamente entre sí que se referencian bajo un mismo
nombre.
Su forma general de
definición es
struct nombre_de_la_estructura{
tipo nombre_variable;
tipo nombre_variable;
tipo nombre_variable;
.
.
}variables_tipo_nombre_de_la_estructura;
donde nombre_de_la_estructura o bien
variables_tipo_nombre_de_la_variables_estructura pueden omitirse pero no ambos.
Ejemplo:
struct agenda{
char nombre[30];
char direccion[20];
char ciudad[15];
int edad;
} actor;
agenda es el nombre de
la estructura. nombre, dirección, ciudad y edad son los campos o elementos de
la estructura y actor es la variable declarada de ese tipo.
Los elementos
individuales de la estructura se referencian utilizando el operador punto. Por
ejemplo: actor.nombre="Harrison
Ford";
Aquí se está asignando
la cadena "Harrison Ford" al campo nombre de la variable actor.
El nombre de la
variable tipo estructura seguido del punto y del nombre del campo, referencia
ese campo individual de la estructura. a todos los elementos de la estructura
se accede del mismo modo. La forma general es:
variable_estructura.nombre_elemento
Así, para imprimir en
pantalla el campo edad de la variable actor, escribimos:
printf("%d",actor.edad);
De la misma forma
podemos utilizar gets (función que lee una cadena desde el teclado) para
obtener un valor para actor, domicilio como se muestra aquí.
gets(actor.domicilio);
Las variables tipo
estructura son útiles para crear unidades de información de diferentes tipos
lógicamente relacionada entre si. Tal es el ejemplo de los datos de una agenda
(en una variable guardas su nombre, dirección, número telefónico, etc.) o de
los datos de un elemento de la tabla periódica (en cada variable guardas su
nombre, símbolo, número atómico, etc.).
INICIALIZACIÓN DE VARIABLES
Inicializar una
variable es darle un valor después que se ha declarado pero antes de que se
ejecuten las sentencias en las que se emplea.
En C, se les puede dar
un valor a la vez que se declaran. Unicamente se coloca el signo igual y una
constante después del nombre de la variable. La forma general de inicialización
es:
tipo nombre_variable =
constante;
int uno=1;
float
pi=3.1416;
char
respuesta='s';
Regularmente, las variables
locales se inicializan cada vez que se entra en el bloque en el que están
definidas mientras que las globales son inicializadas al principio del
programa.
Constantes
Constantes son los
valores que no pueden ser modificados. En C, pueden ser de cualquier tipo de
datos.
Además podemos crear
constantes de caracteres con barra invertida. Estos corresponden a los
caracteres que son imposibles introducir desde el teclado.
Se usan de la misma
forma que los caracteres normales por ejemplo:
printf('Esta es una
prueba\n");
ch='\0';
OPERADORES
Un operador es un
símbolo que indica al compilador que realice manipulaciones lógicas o
matemáticas específicas.
Cuando se aplica el
símbolo / a un entero o a un
caracter, cualquier residuo se trunca. Por ejemplo 5/3 será 1 en división
entera.
El menos monario hace el efecto de
multiplicar su único operando por -1 es decir, cualquier número precedido por
un signo menos cambia de signo.
Incremento y decremento Dos operadores
característicos de C son el incremento y el decremento.++ aumenta en uno a su operando y -- le resta 1. Es decir,
x=x+1 es equivalente a ++x;
x=x-1 es equivalente a –x;
Los operandos de
incremento y decremento pueden ir antes o después del operador sin embargo
existe una diferencia. Veamos el siguiente ejemplo: si x=10;
y=x++; Aquí y tomará el valor de 10. y en
y=++x; y tomará el valor de 11.
Los operadores relacionales son los que
determinan la forma de vinculación entre dos valores. A su vez, los operadores lógicos evalúan la forma de relacionarse los dos valores.
El lenguaje C admite
abreviaturas que simplifican la escritura de ciertos tipos de sentencias de
asignación. Por ejemplo:
x=x+10; es igual a x+=10;
SENTENCIAS DE CONTROL
Son herramientas básicas en la implementación de
programas.
una sentencia puede ser una proposición o
un conjunto de proposiciones (cuando se encuentran agrupadasentre llaves)
SENTENCIAS CONDICIONALES
Las sentencias IF
La sentencia de
control if nos sirve para verificar
que se cumpla una condición en el programa. Su forma general es
if(expresión) sentencia;
else sentencia;
if (divisor!=0)
divisior=dividendo/divisor;
else
printf("Error en
el divisor");
Ifs anidados
La expresión "ifs
anidados" se refiere a que podemos utilizar una sentencia if dentro de otra sentencia if. Esto se emplea cuando se tienen que
cumplir varias condiciones para poder ejecutar una acción.
menu()
{
char opcion;
printf("A)
Español \n");
printf("B)
Matemáticas \n");
scan("%c",&opcion);
printf("Escogió
");
if (opcion=='A')
printf("español");
else if (opcion=='B')
printf("matamáticas");x
else
printf("una asignatura inexisten-
te" );
}
La sentencia Switch
Cuando se anidan
muchos ifs, el código puede volverse
difícil de entender. Para darle mayor transparencia, en C se utiliza la
sentencia de decisión múltiple switch.
Switch es utilizada cuando una variable es
sucesivamente comparada con una lista de enteros o de caracteres. Cuando se
encuentra la correspondencia, se ejecuta una sentencia o el bloque de
sentencias.
La forma general de
una sentencia switch es
switch(expresión)
{
case constante1:
secuencia de sentencias;
break;
case constante2:
secuencia de sentencias;
break;
case constente3:
secuencia de sentencias;
break;
.
.
.
default:
secuencia de sentencias;
}
donde switch es el indicador del tipo de
sentencia de control. { } delimitan
lo que abarca la sentencia switch. case
especifica donde comienza la evaluación de la variable con la constante que
sucede al case
En caso de que
encontremos el valor de la variable en un case se ejecutarán la secuencia de
sentencias relacionadas con este hasta encontrar un break.
Las sentencias
asociadas a Default serán ejecutadas si no se
encuentra ninguna correspondencia con el valor de la variable que estamos
evaluando en alguno de los case.
esta sentencia es opcional.
La diferencia entre switch e if es que la
primera sólo puede comprobar la igualdad, mientras que if puede evaluar
expresiones relacionales o lógicas.
No puede haber dos
constantes case que tengan los
mismos valores sólo en el caso de que la sentencia switch este anidada (que haya una dentro de otra).
menu()
{
char opcion;
printf("A)
Español\n");
printf("B)
Matemáticas\n");
printf("Opción:
");
scan("%c",&opcion);
printf("Escogió
");
switch(opcion)
{
case'A':printf("español");
break;
case
'B':printf("matemáticas");
break;
default: printf("escogiste una asignatura
inexistente");
}
}
Bucles
Se denomina bucles a
las proposiciones de control que nos permiten ejecutar una sentencia hasta que
se cumpla cierta condición. Es decir, si tenemos que realizar una tarea varias
veces, basta con escribirla una sola vez dentro de un bucle, para que pueda
efectuarse las veces que deseamos. Los bucles soportados por C son el for, el while y el do-while.
for(inicialización;condición;incremento) sentencia;
donde Inicialización es una sentencia de
asignación que nos sirve como variable de control del bucle. Condición es una expresión que nos
indica la condición que debe cumplirse para que continue el bucle e incremento define como va cambiando el
valor de la variable de control cada vez que se repite el bucle. Sentencia es el conjunto de
proposiciones que se van a realizar en cada repetición.
main()
{
for(x=1;x<80;x++)
{
gotoxy(x,1);
printf("¾");
gotoxy(x,24);
printf("¾");
}
gotoxy(1,1);
printf("é");
gotoxy(80,1);
Printf("ù");
gotoxy(1,24);
printf("ë");
gotoxy(80,24);
printf("û");
for(x=0;x<24;x++)
{
gotoxy(1,x);
printf("ï");
gotoxy(80,x);
printf("ï");
}
}
Una de las principales
características del for es que la
condición (para determinar si se ejecutan o no las sentencias que contiene) se
evalúa al principio del ciclo. Por esto, el código dentro del bucle no será
ejecutado si la condición es false
al comienzo.
Debido a la
flexibilidad del lenguaje C, se pueden utilizar dos o más variables de control
Por ejemplo:
for
(i=0,j=4;i*j<4;i++,j--)
{
.
.
.
}
En este caso, estamos
inicializando a i y a j dentro del bucle. Al mismo tiempo, en
la sección de incremento, aumentamos a i
y disminuimos el valor de j.
Esto es completamente válido.
Bucle Infinito
Es aquel que no tiene
fin. En este tipo de ciclos, no necesitamos especificar ninguna de las tres
proposiciones que lo constituyen
for (;;)
printf("Bucle infinito");
o basta dejar la de la
condición vacía como se muestra a continuación:
for(x=0;;x++)
printf("Bucle infinito");
La forma de romper un
bucle infinito es mediante la sentencia break.
Cuando se encuentra esta proposición dentro de un ciclo, trunca el bucle y se
procede a ejecutar el código que se encuentra inmediatamente después de él.
main()
}
for(;;)
{
printf("Número: ");
scanf("%d",&x);
if(x==9) break;
}
printf("Digitaste %d números antes de rom-
per el ciclo",x);
}
Bucle sin cuerpo
Según la sintaxis de
C, existen las sentencias vacías por tanto, podemos tener un bucle for o cualquier otro, que no tenga
cuerpo. Este tipo de ciclos se usan regularmente para retardar la ejecución del
programa. Veamos como crear uno:
Ejemplo
6
main()
{
int num;
printf("Piensa un número del 1 al
10.");
lapso();
printf("Que número pensaste: ");
scanf("%d",&num);
.
.
.
}
lapso()
{
int tiempo
int valor=100;
for (tiempo=0;tiempo<valor;tiempo++);
}
En el programa
anterior, se dá cierto tiempo para que pienses un número y luego lo escribas.
While
Este es otro de los
bucles disponibles en C.
while(condición)sentencia;
donde sentencia es una sentencia vacía, una
única o un bloque de sentencias. El bucle itera mientras se cumpla la condición
(puede ser cualquier expresión). Cuando ya no se cumple, el control del
programa pasa a la línea siguiente al código del bucle.
Ejemplo: 1
#include
<ctype.h>
#include<conio.h>
#include <math.h>
main()
{
char respuesta;
clrscr();
respuesta='\0';
while (respuesta!='N')
{
float x;
printf("Dame un número: ");
scanf("%f",&x);
x=fabs(x);
printf("Su valor absoluto es:
%f\n",x);
printf("Presione 'N' para
salir...\n");
respuesta=toupper(getch());
}
}
Inicializamos la
variable respuesta con caracter nulo ('\0')
para asegurarnos de que al menos se entre una vez al ciclo. Al final del bucle,
preguntamos si quiere continuar o no. Con getch()leemos
el caracter. toupper() nos sirve
para convertir el caracter recibido por getch()
a mayúsculas; de esta manera logramos que se acepte 'n' o 'N' para terminar el
ciclo.
Como en el caso del for, podemos utilizar bucles while sin cuerpo. Por ejemplo:
while((letra=getch())!='M');
En letra se guardará
el valor que se lea con getch() y
estos se repetirá hasta que letra sea igual a 'M'.
DO-WHILE
La característica
principal del Do-while es que analiza
la condición del bucle al final del ciclo, lo que garantiza que el bloque de
sentencias se ejecute al menos una vez. Su forma general es
do{
sentencia
}while(condición);
Las llaves no son
necesarias cuando sentencia corresponde
a una sola propo-sición, pero se recomienda que utilizarlas para mejorar la
legibilidad del programa.
Como ejemplo,
modifiquemos el programa anterior utilizando do-while:
Ejemplo: 2
#include
<ctype.h>
#include<conio.h>
#include <math.h>
main()
{
char respuesta;
clrscr();
do{
float x;
printf("Dame
un número: ");
scanf("%f",&x);
x=fabs(x);
printf("Su
valor absoluto es: %f\n",x);
printf("Continuar...\n");
respuesta=toupper(getch());
}while(respuesta!='N');
}
En esta ocasión, no
necesitamos inicializar respuesta ya que por las características de do-while de todos modos se ejecutaría
la primera vez. La única diferencia es que ahora la condición se comprueba al
final del bucle y no al principio como lo hace for ywhile.
Break
La sentencia break tiene dos usos:
1. Para
determinar el final de un case en
una sentencia switch (visto
anterior-mente) y
2. Terminar
la ejecución de un bucle y saltar a la evaluación condicional del ciclo.
Cuando utilizamos una
sentencia break dentro de un bucle,
éste se termina inmediatamente y el control del programa pasa a la línea que
está inmediatamente después del ciclo.
ejemplo: 3
main()
{
int x;
for(x=0;;)
{
if(x==250)
break;
x++;
}
printf("%d",x);
}
El programa anterior
hay un ciclo infinito que es truncado cuando x es igual a 250.
Exit()
Esta sentencia da
lugar a la terminación del programa.
Los programadores la
utilizan cuando no se satisface una condición obligatoria en la ejecución de un
programa ya que detiene su ejecución y fuerza la vuelta al sistema operativo.
La función exit() requiere de un argumento entero
ya que se supone que un proceso de alto nivel sería capaz de acceder al valor
contenido en el argumento . Normalmente se utiliza un argumento 0 (exit(0))
para indicar que se trata de una terminación normal y otros argumentos para
indicar algún tipo de error.
Por ejemplo, imagine
un programa al que se tenga que dar una clave de acceso para iniciar. La
función main() de este programa
sería como esta:
ejemplo 4
main()
{
char clave[]="clave";
char password[5];
printf("Proporcione clave de acceso:
");
scanf("%s",password);
if(password!=clave)exit(1);
.
.
.
}
Al iniciar el
programa, se pide la clave de acceso. En caso de que no sea la especificada, el
programa termina sin esperar nada más.
Continue
Es una sentencia de significado opuesto al
break. En vez de forzar la
terminación del bucle, continue obliga una nueva iteración del ciclo y salta
cualquier código que exista entre este.
ejemplo 5
do{
int
years,tope=12;
gotoxy(5,5);
clreol();
printf("Años: ");
scanf("%d",&years);
if
(years<=0) continue;
if
(years<=tope)
printf("Lo
siento, este programa no es
para niños");
}while(tope!=18);
En el ciclo anterior,
utilizamos el continue para
verificar que la edad se mayor que cero. En caso de que ésta sea cero o menos
vuelve a comenzarlo sin llegar a ejecutar las instrucciones del bucle
restantes. Al no comparar la condición que puede terminar el ciclo, éste se
repite.
FUNCIONES
En C, una función es
un bloque de instrucciones que realizan una tarea específica la cual se maneja
como una unidad lógica. Esta unidad, regresa un valor de acuerdo al resultado
del proceso que realice.
C es un programa de
funciones, todo se hace a partir de ellas. La principal es main() la cual, utiliza a otras que se encuentran definidas en las
bibliotecas (todas las instrucciones que maneja C).
Además de éstas,
nosotros podemos definir nuestras propias funciones. De esta manera dividimos
tareas grandes de computación en varias más pequeñas lo que nos da como
resultado que el programa sea más fácil de entender y se pueda manejar más
eficientemente.
Además, al subdividir
los programas en funciones, éstas pueden ser reutilizadas en otros programas.
La forma general para
definir una función es:
especificador_tipo
nombre_de_la_función (declaración deparámetros)
{
cuerpo de la función
}
El especificador_de_tipo de la función
define la clase de valor que regresa la función. El valor puede ser cualquier
que maneje el C. En caso de que no se especifique ninguno, la función devuelve
por omisión un entero.
Nombre_de_la_función es la palabra con la
que vamos a identificara la función.
La declaración de parámetros
es un conjunto de variables separados por comas y con un tipo de dato
específico que reciben los valores de los argumentos cuando se llama a la
función.
Una función puede
carecer de parámetros en cuyo caso los paréntesis estarán vacíos tanto al
declarar como al mandar llamar a la función.
Por ejemplo:
float
multiplicación (float multiplicando,float multiplicador)
{
multiplicando=multiplicando*multiplicador;
return(multiplicando);
}
La función está
declarada de tipo float porque es la
clase de valor que va a regresar.
Multiplicando y multiplicador es el nombre que le vamos a darlos valores que
recibirá la función para trabajar con ellos los cuales, son declarados dentro
de los paréntesis.
Por último se define
el cuerpo de la función (delimitándose con llaves) .
En este caso,
asignamos el resultado de la multiplicación a multiplicando para ahorrar
memoria (se declara una variable menos) y regresamos el valor obtenido por
medio de la sentencia return.
Return
Esta sentencia se utiliza para devolver valores
generados en una función al programa principal. También sirven para salir de la
función donde se encuentra y continuar con la instrucción posterior a la
función que lo llamó.
En la función anterior
return(multiplicando)devuelve el
contenido de multiplicando al
programa principal. En caso de que sólo se quiera salir de la función, no es
necesario indicarle parámetros, basta con return();.
Todas la funciones,
excepto las de tipo void (Es el tipo
de datos que no tiene valor) generan valores que se transmiten al programa
principal. Estos valores son de tipo int
(entero) por omisión, pero puede regresar los de todo tipo si así se
declara; por ejemplo, en la función de multiplicación,
la función regresa un valor de tipo float
(flotante).
Cuando queremos
utilizar el valor que devuelve la función en el programa principal, es
necesario asignar la función a una variable del tipo de dato que va a regresar
la función.
Reglas de las funciones
·
No se puede declarar funciones dentro de
funciones ya que todas están al mismo nivel,.
·
Tampoco se puede ingresar al código de una
función si estamos fuera de la misma.
·
Las variables que se declaran en las funciones,
son locales y no pueden ser utilizadas fuera de esa función.
·
Además, si utilizamos una función dos o más
veces, la segunda vez las variables locales no contendrán el valor que
obtuvieron al ejecutar la primera vez la función y así sucesivamente ya que se
crean al entrar a la función y se destruyen al salir.
Argumentos
de las funciones:...
Es muy común que las
funciones utilicen argumentos es decir, que necesiten de algún valor o valores
externos dentro de su propio código. Estos valores se pasan mediante variables
llamadas parámetros formales de la función las cuales se declaran dentro de los
paréntesis que suceden a el nombre de la función o bien, después de estos y
antes de la llave de comienzo.
Asegúrese de que de
que los argumentos utilizados al declarar la función sean del mismo tipo que
los usados para llamar la función. Si hay algún error en los tipos, el
compilador no mandará mensaje de error pero se obtendrán resultados
inesperados.
Se puede utilizar a
las variables que son parámetros formales como cualquier otra variable local es
decir, se les puede hacer asignaciones o usarlos en cualquier expresión
permitida por C.
Existen dos formas de
pasar argumentos a una función:
consiste en sólo pasar
el contenido de la variable utilizada como argumento a la subrutina. De esta manera,
los cambios efectuados en los parámetros de la función no afectan a las
variables (globales) que se utilizaron para hacer la llamada a la función.
En la cual, lo que se
pasa a la subrutina es la dirección de la variable que se está mandando como
parámetro. De esta manera, los cambios que sufra el parámetro dentro de la
subrutina, se efectuarán también en la variable que se introdujo como
parámetro.
La forma de pasar una
llamada por referencia es pasando un puntero al argumento, de esta manera, lo
que pasará es la dirección de la variable en vez de su contenido. Para esto,
los parámetros se declaran de tipo puntero.
/* Ejemplo de funciones por valor y por
referencia */
/* Calcula dos veces el porcentaje de gastos, la
primera vez utilizando una función por valor y la segunda por referencia */
main()
{
float
entrada, salida;
clrscr();
printf("Entradas: ");
scanf("%f",&entrada);
printf("Salidad:
");
scanf("%f",&salida);
porcentaje_xvalor(entrada,salida);
/*Llamada a la función porcentaje utilizando paso de
parámetros por valor */
printf("\n\n");
porcentaje_xref(&entrada,&salida);
/*Utilización de la función porcentaje con paso de
parámetros por referencia */
getch();
}
porcentaje_xvalor(float
ingreso, float egreso)
{
egreso=((egreso/ingreso)*100)
printf("Usted gasta el %.2f por ciento de lo que gana",
egreso);
}
porcentaje_xref(float
*ingreso, float *egreso)
{
*egreso=(((*egreso)/(*ingreso))*100);
printf("Usted gasta el %.2f por ciento de lo que gana",
egreso);
}
En el programa
anterior, realizamos la misma tarea dos veces pero de diferente manera.
En porcentaje_xvalor(entrada,salida)
mandamos el contenido de entrada y salida a la función donde son recibidos
por ingreso y egreso respectivamente. De esta manera, el cálculo del porcentaje
se hace internamente es decir, utilizando las variables definidas en la
función. Tanto entrada como salida, no se modifican.
La función porcentaje_xref(&entrada,&salida)
también obtiene el mismo resultado, pero en este caso, en vez de pasar los
valores existentes en las variables, pasamos su dirección; por lo que
trabajamos directamente con ellas dentro de la función aún cuando las llamemos
de diferente manera( ingresos y egresos). En esta ocasión, las
variables globales si se modifican.
Creación de Bibliotecas propias.
Si quiere utilizar
funciones definidas por Ud. en varios programas, puede hacerlo, creando su
propia biblioteca. Esto se logra de la siguiente manera:
·
Defina sus funciones en un nuevo archivo. Mande
llamar las librerías estándar de C, que necesite.
·
No utilice la función main().
·
Compilalo
·
Cuando la compilación sea exitosa, se generará
un archivo con el mismo nombre que el suyo pero con la terminación Obj. Este archivo deberá ser incluido
preferentemente en el mismo directorio que se encuentre la biblioteca . En caso
contrario, se debe dar la ruta en la sección Directories del menú Options.
·
En el programa donde quiera utilizar esta unidad
sólo tendrá que mandarla llamar al principio del programa de la siguiente
manera:
#include "nombre_archivo"
Después de esto, puede
llamar a las funciones que tengas definidas en esta librería normalmente sin
tener que declararlas al principio del programa.
Además de funciones,
en la biblioteca también puede definir constantes, macros, etc.
Programa ejemplo:
/*Programa que
convierte un número en hexadecimal a decimal*/
#include<math.h>
#include<string.h>
#include<conio.h>
void main()
{
char hexa[10];
float numero;
clrscr();
printf("Numero
hexadecimal (mayúsculas): ");
gets(hexa);
numero=hex_dec(hexa);
printf("\n En
decimal es : %.0f",numero);
}
float hex_dec(char cadena[])
{
int i,j;
char letra;
float decimal=0;
float temp=0;
i=strlen(cadena);
for (j=0;i>0;j++,i--)
{
letra=cadena[i--];
switch(letra){
case 1:temp=(1*pow(16,j));
break;
case 2:temp=(2*pow(16,j));
break;
case 3:temp=(3*pow(16,j));
break;
case 4:temp=(4*pow(16,j));
break;
case 5:temp=(5*pow(16,j));
break;
case 6:temp=(6*pow(16,j));
break;
case 7:temp=(7*pow(16,j));
break;
case 8:temp=(8*pow(16,j));
break;
case 9:temp=(9*pow(16,j));
break;
case 0:temp=(0*pow(16,j));
break;
case 'A':temp=(10*pow(16,j));
break;
case 'B':temp=(11*pow(16,j));
break;
case 'C':temp=(12*pow(16,j));
break;
case 'D':temp=(13*pow(16,j));
break;
case 'E':temp=(14*pow(16,j));
break;
case 'F':temp=(15*pow(16,j));
break;
}
decimal+=temp;
}
return(decimal);
}
FUNCIONES
DE ENTRADA Y SALIDA ( )
int
getchar() Esta función leé un caracter desde el teclado hasta que se pulse
<ENTER>.En caso de que se digite máss de un caracter antes de pulsar
<ENTER>, la variable sólo almacenará el primer caracter que se tecleó.
char *gets(char *cad) Esta función leé una cadena de caracteres desde el teclado y la coloca en la cadena cad. Se leen caracteres hasta que se recibe la pulsación de <ENTER>. Esto no quiere decir que en la cadena se almacenará este caracter sino que añadirá un carácter nulo (\0) para identificar el final de la cadena. En caso de error, gets() retorna un puntero nulo y el contenido de cad será indeterminado. Con gets() puedes leer todos los caracteres que desees. Por tanto, corresponde al programador asegurarse que la cantidad de caracteres leídos no superen la capacidad del array.
int
putchar(ch) putchar() escribe un caracter en pantalla donde ch puede ser una
variable de tipo caracter o un caracter ASCII entre comillas simples('') y
posiciona el cursor en la siguiente línea.
int
puts( char *cad) La función puts() escribe en pantalla el contenido de una
cadena apuntada por cad (un conjunto de caracteres) y posiciona el cursor en la
siguiente línea.
int
kbhit() Esta función no está definida por el ANSI propuesto. Sin embargo, la
incluimos aquí porque aunque con nombre diferente, se encuentra definida en
todas las implementaciones de C. Su uso principal es permitir que el usuario
pueda interrumpir alguna rutina desde el teclado. Regresa un valor distinto de
cero, si se ha pulsado una tecla y en caso contrario, el valor retornado es
cero.
int
printf(char *formato, lista_arg) La función printf() despliega en pantalla
tanto cadenas constantes(mensajes) como variables de acuerdo al contenido de
formato. Con formato, se especifica la cadena constante y/o el tipo de
variables que desplegará en pantalla. Todo esto siempre va entre
comillas("") . Por ejemplo:
con
printf("Hola, como estas?"); mandamos un mensaje a pantalla. En este
caso, no es necesario especificar algún formato ya que sólo se despliega el
mensaje.
en
printf("%s",nombre); utilizamos formato para determinar el tipo de
varaible(s) que van a ser desplegadas. determinamos que se va a escribir el
contenido de nombre que es una variable de tipo cadena.
para
definir el contenido de cualquier varibale:
Código Formato
%c Un
sólo caracter
%d Decimal
%i Decimal
%e Notación
científica
%f Coma
flotante
%g utiliza
el más corto de %e o %f.
%o Octal
%s Cadena
de caracteres
%u Decimal
sin signo
%x Hexadecimal
%% Imprimir
el símbolo %
%p Presentar
un puntero
%n El argumento asociado será un puntero entero
en el que se sitúa el número de caracteres escritos hasta entonces.
También podemos desplegar en el monitor mensajes como
el contenido de variables con el mismo comando printf() como en el ejemplo
siguiente:
printf("Hola
%s soy %s, tengo %i años." huesped, nombre, edad);
Si
huesped="visitante", nombre="el supervisor" edad=35
el
resultado será el siguiente mensaje en pantalla:
<Hola
visitante soy el supervisor, tengo 35 años>.
Recuerde
que se deben especificar en el mismo orden tanto el contenido de las variables
a imprimir dentro de formato como las variables en sí.
La
función printf() devuelve el número de caracteres realmente presentados en
pantalla. Un valor negativo significa que se ha producido un error.
Se
pueden escribir enteros entre el signo de porcentaje y el caracter que
especifica el tipo de dato a presentar. Esto sirve para determinar la longitud
del campo, el número de decimales y un indicador de justificación a la
izquierda.
Para
especificar la longitud del campo, basta con escribir el número después del
signo de porcentaje; después se agrega un punto y el número de posiciones decimales
que se desea presentar en el caso de los números en coma flotante. Si la cadena
es mayor que la anchura del campo, se truncan los caracteres por el final.
Por
ejemplo, %12.4f determina a un número de como máximo doce caracteres de
longitud con cuatro posiciones para la parte decimal.
Cuando
se aplica a cadenas de caracteres o enteros, el número después del punto
determina la máxima longitud del campo. Por ejemplo %3.5s presenta una cadena
que tiene al menos tres caracteres y que no excede de cinco. Si la cadena es
mayor que el campo, se truncan los caracteres por el final.
Por
defecto, toda salida está justificada por la derecha. En otras palabras, si la
anchura del campo es mayor que la de los datos presentados, eston son situados
en la parte derecha del campo. Puede forzar que la información quede
justificada a la izquierda situando un signo menos inmediatamente después del
signo de porcentaje. Por ejemplo %-6.3f justifica un número en coma flotante
por la izquierda con tres posiciones decimales en un campo de seis caracteres.
Ejemplo:
Si saludo="hola"
printf("%-10s",saludo); presentará: <hola >
int scanf(char *formato,lista_arg) Esta función
realiza la operación contraria a printf()es decir, leé datos de cualquier tipo
desde el teclado hasta que se pulse un retorno de carro(<ENTER>).
Sus parámetros también son
similares a printf() ya que en formato se especifica el o los tipos de
variables que se van a leer miemtrasq ue en lista_arg se escriben las
variables. Por ejemplo:
scanf("%d",&edad);
scanf("%i%c",&edad,&sexo);
La
sección de formato corresponde a "%d" donde se indica que se va a
leer un entero decimal; &edad corresponde a lista_arg e indica que los
caracteres leídos serán almacenados en la dirección que ocupa la variable edad.
La
diferencia entre la sintaxis de scanf() y printf() consiste en que en la lista
de argumentos, scanf() necesita que se le especifique que el lugar donde va a
almacenar los datos es en la dirección de la variable( &edad). La única
excepción es cuandose va a leer una cadena de caracteres ya que este tipo de
variables indican una dirección por si mismas. Ejemplo:
char
nombre[10];
scanf("%s", nombre);
A
continuación se presentan los códigos de formato descanf().
Código Interpretación
%c Leer
un único caracter
%d Leer
un entero decimal
%i Leer
un entero decimal
%e Leer
un número en punto flotante
%f Leer
un número en punto flotante
%h Leer
un entero corto
%o Leer
un número octal
%s Leer
una cadena de caracteres
%x Leer
un número hexadecimal
%p Leer
un puntero
%n Recibir
un valor entero igual al número de caracteres leídos hasta entonces.
Un
espacio en blanco en la cadena de control da lugar a que scanf() salte uno o más espacios en blanco en
el flujo de entrada. Un caracter blanco es un espacio, un tabulador o caracter
de nueva línea. Esencialmente, un caracter espacio en blanco en una cadena de
control da lugar a que scanf() lea, pero no guarde cualquier número (incluido
0) de espacios en blanco hasta el primer caracter no blanco.
Un
caracter que no sea espacio en blanco hace que scanf() lea y elimine el
caracter asociado. Por ejemplo, %d,%d da lugar a que scanf() lea primero un
entero, entonces lea y descarte la coma, y finalmente lea otro número. Si el
caracter especificado no se encuentra, scanf() termina.
Un
* situado después del % y antes del código de formato leé los datos de tipo
especificado pero elimina su asignación. Asi, dada la entrada 10/20, el código
scanf("%d*%d",&x,&y);
asigna el valor 10 a x, decarta el signo de división, y da a y el valor 20.
Las
órdenes de formato pueden especificar un modificador de máxima longitud de
campo. Situado entre el % y el código de orden de formato, es un entero que
limita la cantidad de caracteres a leer para cualquier campo. Por ejemplo, si
se quieren leer sólo 15 caracteres en nombre se escribiría asi:
scanf("%15s",direccion);
Si
el flujo de entrada fuera mayor de 15 caracteres, entonces una posterior
llamada de entrada debería comenzar donde esta llamada la dejó.P or ejemplo, si
Av._Corregidora_#_500
se ha introducido como respuesta al scanf() anterior, únicamente los primeros
15 caracteres (hasta la a de corregidora) serían situados en dirección debido
al especificador de tamaño máximo. Cuando se hiciera otra llamada a scanf() tal
como scanf("%s",cadena); _#_500 se asignará a cadena.
Cuando
una cadena está siendo leída, los espacios, los tabuladores y los saltos de
línea son utilizados como separadores de campos; sin embargo, cuando se leé un
único caracter, estos son leídos como cualquier otro caracter.
FUNCIONES
DE PANTALLA ( #include<conio.h>
)
clreol()
borra desde la posición del cursor hasta que se alcanza el final de la línea en
el extremo derecho de la pantalla. Esta operación sólo es válida en modo texto.
clreos()
borra la pantalla desde la posición actual del curso hasta abajo. Sólo se
aplica en pantallas en modo texto.
clrscr()
borra toda la pantalla. En general, esta operación sólo se aplica cuando la
pantalla está en modo texto.
gotoxy(int
x, int y) Esta función, sitúa el cursor en la fila y columna definidas por x,
y. Esta operación sólo se utiliza en pantallas de modo texto.
home()
Coloca el cursor en la posición 0,0 (el extremo superior izquierdo de la
pantalla). No borra la pantalla. Sólo funciona en modo texto.
int
gettext(int izq, int top, int der, int centro, void *destino); Copia texto de
la pantalla en modo texto a la memoria. Las coordenadas utilizadas son
absolutas, no relativas a la ventana en la que se está trabajando. La coordenada
del extremo superior izquierdo es (1,1). Regresa un valor diferente de cero si
la operación fue exitosa.
int
movetext(int izq,int top, int der, int centro, int detizq, int desttop); Copia
texto en una pantalla de modo texto de una ventana a otra. Las coordenadas son
relativas al extremo izquierdo de la pantalla (1,1). Regresa un valor diferente
de cero si la operación se efectuó correctamente.
int
puttext(int izq,int top, int der, int centro,void *source); Copia texto de la
memoria a la pantalla. Las coordenadas utilizadas son absolutas, no relativas a
la ventana en la que se esté trabajando. La coordenada del extremo superior
izquierdo es (1,1). Regresa un valor diferente de cero si la operación fué
exitosa.
insline();
Inserta una línea en blanco en una ventana de texto en la posición del cursor.
Las líneas que se encuentran debajo de la posición del cursor se recorren una
línea hacia abajo y se pierde la última línea.
lowvideo(void);
Disminuye la intensidad de la luminosidad de los caracteres. Afecta a todos los
caracteres que se imprimen posteriormente en pantalla dentro de esa ventana.
highvideo(void);
Aumenta la intensidad de la luminosidad de los caracteres. Afecta a todos los
caracteres que se imprimen posteriormente en pantalla dentro de esa ventana.
normvideo(void);
Anula a highvideo() y/o normvideo(). Es decir, la luminosidad de los caracteres
que se escriban a continuación, será normal dentro de esa ventana.
textcolor(int
color); Selecciona un nuevo color de los caracteres que se escribirán a
continuación.
texbackground(int
color); Selecciona un nuevo color de la pantalla.
window(int
iniciox,int inicioy, int finx, int finy); Crea una ventana activa en pantalla.
FUNCIONES MATEMATICAS
( #include<math.h> )
La mayoría de las funciones
matemáticas están definidas con tipo de datos dobles pero podemos utilizar esas
funciones con tipos de datos de menor rango, excepto caracteres.
double
acos(double arg) La función acos() obtiene el arco coseno de arg. EL argumento
de acos() debe estar en el rango de -1 a 1; en cualquier otro caso se produce
un error de dominio.
double
asin(double arg) Esta función devuelve el arco seno de arg. EL parámetro con el
que se mande llamar a asin() debe estar en el rango de -1 a1 para que no
produzca un error de dominio.
double
atan(double arg) Devuelve el arco tangente de arg .
double
atan2(double y, double x) atan2() devuelve el arco tangente de y/x. Utiliza el
signo desus argumentos para obtener el cuadrante del valor devuelto.
double
ceil(double num) Esta función da como resultado un valor double que representa
el entero más pequeño que es mayor o igual a num. Por ejemplo, dado 1.02,
ceil() devuelve 2.0; dado -1.02, devuelve-1.
double
cos(double arg) Esta función devuelve el coseno de arg. El valor de arg debe
darse en radianes.
double
cosh(double arg) cosh() devuelve el coseno hiperbólico de arg. El valor de arg
debe darse en radianes.
double
exp(double arg) La función exp() devuelve un número e elevado a la potencia
arg.
double
fabs(double num) Devuelve el valor absoluto de num.
double
floor(double num) La función floor() el mayor entero (representado en double)
que no es mayor que num. Por ejemplo, dado 1.02, floor() devuelve 1.0; dado
-1.02,floor() devuelve -2.0
double
fmod(double x, double y) Esta función retorna el residuo de la división entera
x/y.
double
frexp(double num, int *exp) La función frexp() descompone el número num en una
mantisa de rango entre 0.5 y 1 y en un exponente entero tal
quenum=mantisa*2exp. Se devuelve la mantisa, y el exponente se guarda en la
variable apuntada por exp.
double
idexp(double num, int exp) Esta función regresa el valor de num*2exp. Si se
produce desbordamiento, se devuelve HUGH-VAL (constante definida por C).
double
log(double num) La función log() devuelve el logaritmo neperiano de num. Se
produce un error cuando num es negativo y error de rango si el argumento es
cero.
double
log10(double arg) Esta función, regresa el logaritmo en base 10 de num. Se
produce un error de dominio si el argumento es negativo, y un error de rango en
caso de ser cero.
double
modf(double num, int i) Esta función descompone num en su parte entera y
fraccionaria, y sitúa la parte entera en la variable apuntada por i.
double
pow(double base, double exp) retorna base elevada a exp, esto es base exp. Se
produce un error de dominio si base es cero y exp es menor o igual a cero.
También ocurre si base es negativo y expno es entero. Un desbordamiento produce
un error de rango.
double
sin (double arg) Devuelve el seno de arg. El valor de arg, debe darse en
radianes.
double
sinh(double arg) devuelve el seno hiperbólico de arg. El valor de arg debe
darse en radianes.
double
sqrt(double num) devuelve la raíz cuadrada de num. Si se llama con un número
negativo, se produce un error de dominio.
double
tan(double arg) Esta función, devuelve la tangente de arg. El valor de arg debe
darse en radianes.
double
tanh(double arg) retorna la tangente hiperbólica de arg. El valor devuelto debe
darse en radianes.
FUNCIONES
DE HORA, FECHA Y OTRAS RELACIONES CON EL SISTEMA. ( #include <time.h> )
char
*asctime(punt)
struct
tm *punt
Esta función regresa un puntero a una cadena que
convierte la información almacenada en la estructura apuntada por punt de la
forma siguiente:
dia
mes horas:minutos:segundos año\n\0
Por
ejemplo:
Miercoles
Jun 19 12:05:34 1999
El
puntero a estructura pasado a asctime() se obtiene generalmente de localtime()
o gmtime().
El
buffer utilizado por asctime() para mantener la cadena de salida con formato se
situa estáticamente
en un array de caracteres y se sobre escribe cada vez que se llama a la
función. Si se desea salvar el contenido de la cadena, es necesario copiarlo en
otro lugar.
clock_t_clock()Indica
el tiempo empleado en la ejecución de un proceso. Para transformar este valor
en segundos, se divide entre el valor de la macro CLK_TCK. Se devuelve el valor
-1 si el tiempo no está disponible.
char *ctime(long *hora)
long *ctime(long *hora)
Dado
un puntero a la hora de calendario, la función ctime()convierte un tiempo
almacenado como un valor de tipo time_t a una
cadena de caracteres de la forma:
dia
mes fecha horas:minutos:segundos año\n\0
La
hora de calendario se obtiene normalmente durante una llamada atime().
La
función ctime() es equivalente a:
asctime(localtime(hora))
El buffer utilizado por ctime() para guardar la cadena de salida conformato se
sitúa de forma estática en un array de caracteres y se sobreescribe cada vez
que se llama a la función. Si se desea guardar el contenido de la cadena es necesario guardarla en otro lugar.
double
difftime( time_t hora1, tiem_t hora2) Esta función devuelve la diferencia en
segundos que tarda en finalizar el bucle for desde 0 hasta 500000.
struct
tm *gmtime(time_t hora) regresa un puntero a la forma separada de hora en una
estructura tm. Esta, está representada en hora de Greenwich. El valor de hora
se obtiene normalmente a través de una llamada a time().
La estructura utilizada por gmtime() mantiene la hora
separada en una posición estática y se sobre escribe en ella cada vez que se
llama a la función. Si se desea guardar el contenido de la estructura es
necesario copiarlo en otro lugar.
struct
tm *localtime(time_t *hora) devuelve un puntero a la forma separada de hora en
la estructura tm. La hora se representa con la hora local. Esta se obtiene
normalmente a través de una llamada a time().
La estructura utilizada por localtime() para mantener
la hora separada, se situada de forma estática y se reescribe cada vez que se
llama a la función. Si se desea guardar el contenido de la estructura, es
necesario copiarla en otra variable.
time_t
mktime(struct tm *hora) se utiliza principalmente para inicializar la hora del
sistema. Los elementos tm_wday y tm_yday son activados por la función, de modo
que no necesitan ser definidos en el momento de la llamada.
Si mktime() no puede representar la información como
una horade calendario válida, se devuelve -1.
char *setlocale(int categoria, char lugar) permite al
usuario pedir o activar ciertos parámetros que son sensibles al lugar donde se
utiliza el programa. Por ejemplo, en Europa, la coma se utiliza en lugar del
punto decimal; del mismo modo los formatos de la hora y la fecha difieren.
Si
lugar es nulo, setlocale() devuelve un puntero a la actual cadenade
localización especificada para poner los par metros de lugarsegún se
especifica en categoría.
En
el momento de la llamada, categoría debe ser una de las siguientes macros:
LC_ALL
LC_COLLATE
LC_CTYPE
LC_NUMERIC
LC_TIME
LC_ALL
hace referencia a todas las categorías de localización. LC_COLLATE afecta a la
operación de la función strcoll(). LC_CTYPE modifica la forma de trabajo de las
funciones de caracteres. LC_NUMERIC cambia el caracter del mundo decimal para
las funciones de entrada/salida con formato, Finalmente, LC_TIME determina el
comportamiento de la función strftime(). El estándar define dos posibles
cadenas para lugar. La primera es "C", que especifica el mínimo
entorno para la compilación de C. El segundo es " ", la cadena vacía,
que especifica el entorno de implementación definido por defecto. El resto de
los valores definidos para locale() están definidos por la implementación y
afectan a la portabilidad.
time_t time(time_t hora) devuelve la hora actual del
calendario del sistema. Si el sistema no tiene hora, devuelve -1.
Puede llamarse con un
puntero nulo o con un puntero a una variable de tipotime_t. Si se utiliza este
último, el argumento también es asignado a la hora de calendario.
( #include <ctype.h> )
int isalnum(int
ch) devuelve un valor distinto de cero en caso de que ch sea una letra del
alfabeto o un dígito; si no, devuelve cero.
int isalpha(int
ch) si ch es una letra del alfabeto, regresa un valor diferente de cero, en
cualquier otro caso, devuelve cero.
int iscntrl(int
ch) determina si ch es un caracter de control - entre 0 y 0x1F (0 a 31 en decimal)
o si ch es igual a 0x7F(la tecla DEL)- en cualquier todo caso, devuelve cero.
int isdigit(int
ch) devuelve un valor distinto de cero si ch es un número dígito (desde 0 a 9).
De lo contrario, devuelve cero.
int isgraph(int
ch) comprueba si ch es un carácter imprimible distinto del espacio en blanco;
si no es así, devuelve cero como resultado de la ejecución.
int islower(int
ch) devuelve un valor distinto de cero cuando ch es un caracter en minúscula es
decir, una letra desde a hasta z; en cualquier otro caso devuelve cero.
int isprint(int
ch) verifica que ch sea un carácter imprimible, incluyendo el espacio en
blanco; en cualquier otro caso, se devuelve cero.
int ispunct(int
ch) comprueba que ch sea un caracter de puntuación, excluyendo el espacio en
blanco; en cualquier otro caso devuelve cero. En puntuación se incluye a todos
los caracteres que no son alfanuméricos ni el espacio en blanco
int isspace(int
ch) Esta función, devuelve un valor diferente de cero en caso de que ch sea el
espacio en blanco, el tabulador o un caracter de salto de línea; en cualquier
otro caso, devuelve cero.
int isupper(int
ch); comprueba que ch sea una letra mayúscula(cualquier letra entre A y Z); en
caso contrario devuelve cero.
int isxdigit(int
ch) devuelve un valor distinto de cero si ch es un dígito hexadecimal; en caso
contrario, devuelve cero.
void *memchr(void
*buffer,int ch, unsigned int cuenta) busca en buffer la primera ocurrencia de ch
en los primeros cuenta caracteres. La función regresa un puntero a la primera
ocurrencia del caracter ch en buffer. Si no se encuentra ch se devuelve un
puntero nulo.
int memcmp(void
*buf1,void *buf2,unsigned int cuenta) Esta función compara lexicográficamente
los primeros cuenta caracteres de los arreglos buf1 y buf2. memcmp() devuelve
un entero que se interpreta acorde a lo siguiente:
Valor Interpretación
Menor que
0 buf1 es menor que buf2
0 buf1 es iguala buf2
Mayor que
cero buf1 es mayor que buf2.
void memcpy(void
*hacia, void *desde, unsigned int cuenta) Esta función sirve para copiar cuenta
caracteres del arreglo desde en el arreglo hacia. Si los arreglos se
superponen, el comportamiento de memcpy()queda indefinido. Como resultado,
devuelve un puntero a hacia.
void *memset(void
*buf, int ch, unsigned int cuenta) copia el byte menos significativo de ch en
los primeros cuenta caracteres del arreglo apuntado por buf. Devuelve buf. El
uso más común de memset() es dar valor inicial una región de memoria con algún
valor conocido. En caso de que el compilador no soporte el tipo void.
char *strcat(char
*cad1, char *cad2) Esta función concatena una copia de cad2 en cad1 y añade al
final de cad1 un caracter nulo. El caracter nulo determinación que originalmente
tenía cad1 es sustituido por el primer caracter de cad2. La cadena cad2 no se
toca en esta operación. La función devuelve cad1. Es necesario que cad1 sea lo
suficientemente grande como para mantener su contenido original y el de cad2.
char *strchr(char
*cad, int ch) devuelve un puntero a la primera ocurrencia de ch en la cadena
apuntada por cad. Si no se encuentra, devuelve un puntero nulo.
unsigned int strcoll(char
*hacia, unsigned int cuenta, char *desde) se utiliza para ajustar la cadena
apuntada por desde de modo que pueda ser utilizada por memcmp() ostrcmp() según
se requiera. El resultado de tal ajuste se sitúa en la cadena apuntada por
hacia hasta la longitud que cuenta especifica. En ningún caso, sin embargo, la
longitud de la cadena apuntada por hacia debe superar el doble de la longitud
de la cadena apuntada por desde. La función devuelve la longitud de hacia si se
ejecuta correctamente, si no la función devuelve cero.
int strcmp(char
*cad1, char *cad2) Por medio de esta función se comparan lexicográ-ficamente
dos cadenas que finalizan con el caracter nulo y devuelve un entero que se
interpreta de la siguiente forma:
Valor Interpretación
Menor que
0 cad1 es menor que cad2
0 cad1 es iguala cad2
Mayor que
0 cad1 es mayor que cad2
char *strcpy(char
*cad1, char *cad2) se utiliza para copiar el contenido de cad2 encad1. La
variable cad2 debe ser un puntero a una cadena que finalice con un caracter
nulo; strcpy() devuelve un puntero acad1. Si cad1 y cad2 se solapan, el
com-portamiento de strcpy() es indefinido.
int strcspn(char
*cad1, char *cad2)11 devuelve el índice (la dirección)del primer caracter en la
cadena apuntada por cad1 que está como caracter de la cadena apuntada por cad2.
char *strerror(int
num_error) Esta función convierte el número de error especificado por num_error
en una cadena de mensaje de error. Regresa un puntero a la cadena. El mensaje a
cada num_error está definido en la aplicación. Bajo ninguna circunstancia se
debe modificar la cadena.
unsigned int strlen(char
*cad) nos sirve para determinar el número de caracteres que continúe una cadena
que finaliza con el caracter nulo. El caracter nulo no se contabiliza.
char *strncat(char
*cad1,char *cad2, unsigned int cuenta) concatena cuenta caracteres de la cadena
apuntada por cad2 en la cadena apuntada por cad1 y pone al final de cad1 el
caracter nulo. El caracter nulo que tenia inicalmentecad1 es sustituido por el
primer caracter de cad2. La cadenacad2 no se toca. strncat() devuelve cad1. no
se hacen comprobaciones de límites. Así que es necesario asegurarse que cad1
sea lo suficientemente grande como para mantener su contenido original y el de
cad2.
int strncmp(char
*cad1,char *cad2, unsigned int cuenta) Esta función compara lexicográficamente
un máximo de cuenta caracteres de las dos cadenas terminadas con un caracter
nulo y devuelve un entero cuyo significado se presenta a continuación:
Valor Interpretación
Menos que
0 cad1 es menor que cad2
0 cad1 es iguala cad2
Mayor que
0 cad1 es mayor que cad2
char *strncpy(char
*cad1,char *cad2, unsigned int cuenta) copia cuenta caracteres de la cadena
apuntada por cad2 en la cadena apuntada por cad1 . El elemento cad2 debe de
tener un caracter final de cadena nulo. La función devuelve un puntero a cad1.
Los caracteres nulos al final,
indican el final de la cadena.
Si cad1 y cad2 se solapan,
el comportamiento destrncpy() está indefinido. Si la cadena apuntada por cad2
contiene menos caracteres que los indicados por cuenta, se añaden caracteres
nulos al final de cad1 hasta que se copie cuenta caracteres. En cambio, si la
cadena apuntada por cad2 es mayor que cuenta, la cadena resultante apuntada por
cad1 no tiene caracter nulo de terminación.
char strpbrk(char
*cad1, char *cad2) compara caracter a caracter de cad1 con cad2 y devuelve un
puntero al primer caracter de la cadenas que se correspondan (sean los mismos).
El caracter nulo de terminación no se incluye. Si no hay correspondencia se
devuelve un puntero nulo.
char *strrchr(char
*cad, int ch) devuelve un puntero a la última ocurrencia del byte menos
significativo de ch en la cadena apuntada por cad o un puntero nulo si no se
encuentra.
int strspn(char
*cad1, char *cad2) Esta función devuelve la longitud de la sub cadena inicial
apuntada por cad1 que está constituida sólo por aquellos caracteres contenidos
en la cadena apuntada por cad2. Es decir, strspn()devuelve el índice del primer
caracter en la cadena apuntada por cad1 que no se corresponde con ningún
caracter de la cadena apuntada por cad2.
char *strstr(char
*cad1,char *cad2) devuelve un puntero a la dirección de la primera ocurrencia
en la cadena apuntada por cad1 de la cadena apuntada por cad2 excepto el
caracter nulo de terminación decad2. Si no la encuentra, devuelve un puntero
nulo.
char *strtok(char
*cad1, char *cad2) Esta función devuelve un puntero a la siguiente palabra de
la cadena apuntada por cad1. Los caracteres que constituyen la cadena apuntada
por cad2 son los delimitadores que identifican la palabra. Se devuelve un
puntero nulo cuando no existe ninguna palabra que devolver.
La primera vez que se llama
a strtok(), cad1 se utiliza realmente en la llamada. Las llamadas posteriores
utilizan un puntero nulo para el primer argumento. De esta forma, la cadena
completa se puede reducir a sus palabras.
Es importante entender que
esta función modifica la cadena apuntada por cad1. Cada vez que se encuentra
una palabra se pone un carácter nulo donde estaba el delimitador. De esta
forma, strtok() puede continuar avanzando por la cadena. Nótese que la cadena
inicial es, por tanto, destruida.
Es posible utilizar un
conjunto diferente de delimitadores para cada llamada strtok().
int tolower(int
ch) Mediante esta función se regresa el equivalente en minúsculas de ch si ch
es una letra; en cualquier otro caso devuelve ch sin modificar.
int toupper(int
ch) devuelve la mayúscula de ch si ch es una letra; en cualquier otro, devuelve
ch sin modificar.
OTRAS FUNCIONES)
#include<assert.h>
void assert(exp)
/* exp es cualquier expresión válida en C*/ escribe la información de error en
stderr y entonces aborta la ejecución del programa si la expresión exp tiene el
valor de cero. En cualquier otro caso, assert() no hace nada.
·
La macro assert() se utiliza normalmente para ayudar a
verificar que un programa opera correctamente. La expresión se dispone de modo
que se evalúe a true (regrese un valor diferente de cero) sólo cuando no han
tenido lugar errores.
·
No es necesario eliminar las sentencias assert() del código
fuente una vez que el programa se haya depurado, ya que si la macro NDEBUG
aparece definida (como cualquier otra) entonces las macros assert() son
ignoradas.
(include<stdlib.h>
void abort()da
lugar a la terminación auto-mática del programa. Ningún archivo es volcado. En entornos
que lo soportan, abort() devuelve un valor definido por la aplicación al
proceso que haya hecho la llamada (normalmente el sistema operativo). Su uso
principal es prevenir una fuga del programa cerrando los archivos activos.
int abs(int num) devuelve el valor absoluto del
entero num.
int atexit(func) void (*func)();
La función atexit() fija la
función apuntada por func como la función a ser llamada una vez alcanzada la
terminación normal del programa.
La función atexit()
devuelve cero si la función queda establecida como función de terminación; en
cualquier otro caso devuelve un valor distinto de cero.
·
El estándar ANSI propuesto especifica que al menos se pueden
fijar32 funciones de terminación siendo llamadas en orden inverso al de su establecimiento.
En otras palabras, la naturaleza del proceso de registro es como una pila.
·
La función atexit() se llama algunas veces onexit()por
compiladores que desvían ligeramente del estándar propuesto.
double atof(char
*cad Esta función devuelve la cadena apuntada por cad a un valor de tipo
double. La cadena debe tener un número válido en punto flotante. Esto incluye
espacios en blanco, signos de puntuación distintos del punto, y caracteres que
no sean E o e. esto supone que si atof()se llama con la cadena
"100.00HOLA" se devuelve el valor 100.00.
int atoi(char
*cad) convierte la cadena apuntada por cad a un valor int. La cadena debe
contener un número entero válido. Si este no es el caso, el valor devuelto
queda indefinido.
·
El número puede acabar con cualquier caracter que no forme
parte de un número entero. Esto incluye espacios en blanco, signos de
puntuación y otros que no sean dígitos. Esto supone que si atoi() se llama con
123.23 se devuelve el valor entero 123 y el .23se ignora.
int atol(char
*cad) convierte la cadena apuntada por cad aun valor long int. La cadena debe
contener un número entero de tipo long válido. Si no es este el caso, el valor
devuelto queda indefinido.
·
El número puede acabar con cualquier caracter que no forme
parte de un número entero. Esto incluye espacios en blanco, signos de
puntuación y otros que no sean dígitos. Esto supone que si atol() se llama con
123.23 se devuelve el valor entero 123 y el .23se ignora.
void *bsearch(void*clave, void *base, unsigned int
num, unsigned int tam, int (*compara)(); La función bsearch() realiza una búsqueda binaria en un arreglo ordenado donde
clave es el objeto a buscar, base es un puntero al primer elemento del arreglo.
El número de elementos en el arreglo está especificado por num y el tamaño (en
bytes)de cada elemento está descrito en tam. La función apuntada compara se
utiliza para comparar un elemento del arreglo con la clave. La forma de la
función de comparación debe ser .
compara(void
*elemento1,void *elemento2)
Debe devolver los
siguientes valores:
Si elemento1 es menor que
elemento2, devuelve un valor menor que cero.
Si elemento1 es igual que
elemento2, devuelve cero.
Si elemento1 es mayor que
elemento2, devuelve un valor mayor que cero.
·
El arreglo debe estar ordenado en orden ascendente con la
menor dirección conteniendo al elemento más pequeño. Si el arreglo no contiene
la clave, se devuelve un puntero nulo.
·
La mayor parte de los compiladores que no son completamente
compatibles con el estándar ANSI propuesto, sustituyen los punteros void por
punteros char en esta definición y usan un molde de tipo cuando trabajan con
otros tipos de datos.
void exit(int
estado) da lugar inmediatamente a la terminación normal de un programa. El
valor de estado se pasa al proceso de llamada - normalmente el sistema
operativo- si el entorno lo soporta. Por convenio, el valor de estado es 0,
cuando se ha producido una terminación normal del programa. Un valor distinto
de cero puede utilizarse para indicar un error definido por la aplicación.
div_t div(int
numer, int denom) devuelve el cociente y el resto de la operación numer/denom.
El tipo de estructura div_t está definido en stdlib.h y tiene al menos estos
dos campos:
int quot; /*el cociente*/
int rem /*el resto*/
int itoa(
int num, char cad, int radix) convierte el entero num a su cadena equivalente y
sitúa el resultado en la cadena apuntada por cad. La base de la cadena de
salida se determina por radix, que se encuentra normalmente en el rango 2 a 16.
La función itoa devuelve un
puntero a cad. Generalmente no devuelve valor de error. Asegúrese al llamar a
itoa() que la cadena es lo suficientemente grande como para contener el
resultado transformado.
Su uso principal es
convertir tipos de datos enteros a cadenas de modo que pueden ser enviados a un
dispositivo no soportado directamente por el sistema de E/S usual de C - es
decir, a un dispositivo no de flujo -. Lo mismo se puede utilizar con printf().
long labs(long
num) Al ejecutar esta función labs() se devuelve el valor absoluto de num, un
long int.
ldiv_t
ldiv(long int numer, long int denom) Devuelve el cociente y el
resto de la operación numer/denom que son números enteros de tipo long.
El tipo de estructura
ldiv_t está definido en stdlib.h y tiene al menos estos dos campos:
int quot; /*el cociente*/
int rem /*el resto*/
int ltoa(
int long num, char cad, int radix) convierte el entero num de tipo long a su
cadena equivalente y sitúa el resultado en la cadena apuntada por cad. La base de
la cadena de salida se determina por radix, que se encuentra normalmente en el
rango 2 a 16.
La función ltoa() devuelve
un puntero a cad. Generalmente no devuelve valor de error. Asegúrese al llamar
a ltoa() que la cadena es lo suficientemente grande como para contener el
resultado transformado.
Su uso principal es
transformar enteros en cadenas de modo que pueden ser enviados a un dispositivo
no soportado directamente por el sistema de E/S usual de C - es decir, a un
dispositivo de no flujo-. Lo mismo se puede utilizar con printf().
void perror(char
*cad) proyecta el valor de la variable global errno en una cadena y escribe
esta cadena en stderr. Si el valor de cad no es nulo, la cadena se escribe
primero seguida de dos puntos, y después por el propio mensaje de error.
void qsort(base, num, tam,(compara))
void
*base;
unsigned
int num, tam;
int (*compara)(elemento1,elemento2);
const void
*elemento1;
const void
*elemento2;
Esta función ordena un
arreglo, utilizando el algoritmo de ordenación quic-ksort. Esta función no
retorna valor alguno.
·
La variable base es un puntero al primer elemento de un
arreglo. num es el número de elementos del arreglo. bytes es la longitud en
bytes de un elemento.
·
compara es un puntero a una función definida por el usuario,
que compara dos elementos y retorna valor: Si elemento1 es menor que elemento2
devuelve un valor menor que cero. Si elemento1 es igual a elemento2 devuelve
cero. Si elemento1 es mayor que elemento2 devuelve un valor mayor que cero.
·
El arreglo es ordenado en forma ascendente con la dirección
más pequeña conteniendo el menor elemento.
·
Se sustituyen por punteros de tipo char los punteros de tipo
void en los compiladores que no son totalmente compatibles con el compilador
estándar.
int rand()
genera un flujo de números pseudo aleatorios. Cada vez que se llama, se
devuelve un entero entre 0 y RAND_MAX.
void srand(unsigned
int semilla) utiliza semilla para fijar un punto de partida para el flujo
generado por rand(), que devuelve números pseudo aleatorios.
La función srand() se
utiliza normalmente para permitir que ejecuciones múltiples de un programa
utilicen diferentes flujos de números pseudo aleatorios.
long int strtol(char
*ini, char *fin, int radix) Convierte la representación en cadena de caracteres
de un número- almacenada en la cadena apuntada por ini- en un número de tipo
long int y devuelve el resultado. La base del número está determinada por
radix. Si radix es 0, debe estar en el rango de 2 a 36.
La función
strtol() trabaja de la siguiente forma: primero elimina cualquier espacio en
blanco de la cadena apuntada por ini. A continuación, se lee cada uno de los
caracteres que constituyen el número . Cualquier caracter que no pueda formar
parte de un número de tipo long int finaliza el proceso. Por último, fin se
deja apuntando al resto, si lo hay, de la cadena original. Esto supone que si
strtol() se llama con 100.000 pliers, se devuelve el valor de 100L y fin apunta
al espacio que precede a pliers.
Si se
produce un error de conversión, strtol() devuelve LONG_MAX para desbordamiento
o LONG_MIN para desbordamiento por abajo. Si no se produce la conversión, se
devuelve cero.
unsigned long int strtoul(char *ini, char *fin, int radix) Convierte la
representación en cadena de caracteres de un número- almacenada en la cadena
apuntada por ini- en un número de tipo long int y devuelve el resultado. La
base del número está determinada por radix. Si radix es 0, la base viene
determinada por las reglas que gobiernan la especificación de constantes. Si radix
está especificada, debe estar en el rango de 2 a 36.
La función strtoul()
trabaja de la siguiente forma: primero elimina cualquier espacio en blanco de
la cadena apuntada por ini. A continuación, se lee cada uno de los caracteres
que constituyen el número . Cualquier caracter que no pueda formar parte de un
unsigned long int da lugar a que el proceso se detenga. Esto incluye espacios
en blanco, puntuación y caracteres. Finalmente, fin se deja apuntando al resto,
si lo hay, de la cadena original. Esto supone que si strtoul() se llama con
100.000 pliers, se devuelve el valor de 100L y fin apunta al espacio que
precede a pliers.
Si se produce un error de
conversión, strtoul() devuelve ULONG_MAX para desbordamiento o ULONG_MIN para
desbordamiento por abajo. Si no se produce la conversión, se devuelve cero.
int system(char
*cad) pasa la cadena apuntada por cad como una orden al procesador de órdenes
del sistema operativo. El system() se llama con un puntero nulo, devuelve un valor
distinto de cero si está presente un procesador de órdenes; en cualquier otro
caso devuelve 0. Esta función devuelve cero si fue completamente ejecutada; en
cualquier otro caso devuelve un valor distinto de cero.
Programa ejemplo
El siguiente programa,
contiene una función que valida que únicamente se lean números enteros y otra
que sólo reciba letras.
#include <stdio.h>
#include<string.h>
void main()
{
int cifra;
char word[20];
clrscr();
switch(menu())
{
case 1: cifra=numeros();
printf("\n%d",cifra);
break;
case 2:
captura(word);
printf("\n%s",word);
break;
default:
exit(0);
}
getch();
}
captura(char
palabra[])
{
char *letra;
char alfabeto[]="ABCDEFGHIJKLMN¥OPQRSTUVWXYZabcdefghijklmnñopqrstuvwxyz";
int i;
palabra[0]='\0';
clrscr();
do
{
*letra=getch();
for
(i=0;i<=53;i++)
{
if
(alfabeto[i]==*letra)
{
printf("%c",*letra);
strcat(palabra,letra);
break;
}
}
}while((*letra!=13) &&
(strlen(palabra)<20));
}
numeros()
{
char cadena[10];
char car='\0';
int i=0;
int cantidad;
do
{
car=getch();
switch(car)
{
case'0':
cadena[i]=car;
printf("%c",car);
break;
case'1':
cadena[i]=car;
printf("%c",car);
break;
case'2':
cadena[i]=car;
printf("%c",car);
break;
case'3':
cadena[i]=car;
printf("%c",car);
break;
case'4': cadena[i]=car;
printf("%c",car);
break;
case'5':
cadena[i]=car;
printf("%c",car);
break;
case'6':
cadena[i]=car;
printf("%c",car);
break;
case'7':
cadena[i]=car;
printf("%c",car);
break;
case'8':
cadena[i]=car;
printf("%c",car);
break;
case'9':
cadena[i]=car;
printf("%c",car);
break;
default:
i--;
break;
}
i++;
}while((car!=13)
&& (i<5));
cantidad=atoi(cadena);
return(cantidad);
}
menu()
{
int numero;
printf("Escoge una opción:\n");
printf("1.Escribir sólo
números\n");
printf("2.Escribir
únicamenteletras\n");
printf("Opción: ");
scanf(" %d",&numero);
return(numero);
}
En los arreglos con
tamaño, se tiene que calcular que la longitud del arreglo sea lo
suficientemente grande para que fueran almacenados todos los elementos que se
desean. Si se tuviéra que inicializar varios arreglos de cadena seria
fastidioso contar cuantos caracteres ocupa cada arreglo.
Es posible que C
calcule automáticamente la longitud del arreglo utilizando la inicialización de
arreglos indeterminados la cual permite que el compilador de C cree
automáticamente un arreglo suficientemente grande para mantener todos los
inicializadores presentes si el tamaño del arreglo no está especificado.
El uso de la
inicialización de los arreglos indeterminados permite al programador cambiar el
contenido de cualquiera de las cadenas sin tener que reconsiderar el tamaño del
arreglo. También puede utilizarse en arreglos multidimensionales. En este caso,
se debe especificar todo, sin considerar la dimensión que se encuentra más a la
izquierda para permitir al compilador de C indexar el arreglo adecuadamente. El
método es similar a la especificación de parámetros de un arreglo. De este modo
se pueden construir tablas de longitudes variables, y el compilador asignará
automáticamente el espacio suficiente para ellas.
La ventaja de este
tipo de declaración sobre la versión del tamaño determinado es que la tabla
puede alargarse o acortarse sin cambiar las dimensiones del arreglo.
Éste tipo de arreglos
se utiliza principalmente para mantener punteros a mensajes de error.
Por ejemplo, podemos
crear una función que muestre un mensaje de error determinado y su número
correspondiente.
error(int numero)
{
static
char*err[]={
"Errorde
punto flotante\n",
"Errorde sintaxis\n",
"Número demasiado pequeño\n",
"Númerodemasiado grande\n"
};
printf("Error %d:
%s" número, err[numero]);
}
La función anterior
recibe un entero como parámetro. Este indica el número de elemento del array
que contiene el apuntador al primer elemento de la cadena de caracteres que
corresponde. Tanto el número de error (número de elemento) como su mensaje de
error correspondiente se presentan en pantalla.
Un puntero a puntero
es una forma de indirección múltiple, o un encadenamiento de punteros. Sabemos
que un puntero es una variable que contiene la dirección de un valor
determinado. Un puntero a puntero es una variable que contiene la dirección del
lugar que contiene la dirección de una variable.
Una variable que es un
puntero a puntero tiene que declararse como tal. Esto se hace colocando un *
adicional del lado izquierdo del nombre dela variable. Por ejemplo:
double ** tolerancia;
Esta declaración le indica
al compilador que la variable tolerancia es un puntero a un puntero que
contiene la dirección de una variable de tipo double.
Veamos un ejemplo:
main()
{
int n,*p,**q;
n=5;
p=&n;
q=&p;
printf("%d",**q)
/*imprimireel valor de x*/
}
Aquí, n está declarado
como un entero, p como un puntero a entero y q como un puntero a puntero a
entero. Las asignaciones de la función nos d n una idea de como se
relacionan las tres variables entre si: El contenido de la variable n es 5; a
su vez, asignamos al puntero p la dirección de la variable que contiene ese
número. Finalmente, como q es un puntero a un puntero, sólo puede contener
direcciones por tanto, guarda la dirección de la variable donde se encuentra el
valor de la dirección donde se encuentra el 5.
Mediante la llamada a
printf() comprobamos lo dicho, ya que despliega el contenido de número a pesar
de que es llamado desde una variable puntero a puntero.
Problemas con punteros
Utilizar punteros
dentro de la programación es necesario en la implementación de algunos
programas. Por ahora, no te preocupes sino encuentras el uso práctico de esta
herramienta. Conforme vayas dominando tanto la programación como el lenguaje C,
te dar s cuenta de las formas en que puedas aplicarlo. Sin embargo, es muy
fácil cometer errores al utilizarlos ya que nada da más problemas que un
puntero descontrolado.
Un puntero erróneo es
difícil de encontrar porque el problema es que cada vez que se realiza una
operación utilizando ese puntero, se está leyendo o escribiendo en algún lugar
desconocido de la memoria. Si se leé de él, lo peor que puede ocurrir es que se
obtenga basura. Sin embargo, si se escribe en él, se est escribiendo en
otras partes de código o datos. El hecho de estar perdiendo datos, puede
hacerse evidente hasta la ejecución del programa, y los datos perdidos pueden
llegar a ver el fallo en un lugar erróneo. Puede haber poca o ninguna evidencia
de que el puntero sea el problema. Este tipo de errores hace que los programadores
pierdan el sueño y el tiempo una y otra vez.
Lo mejor para evitar
este tipo de errores, es prevenirlos. En esta sección te mostramos los errores
m s frecuentes que se cometen en la utilización de punteros:
Puntero no
inicializado
Se incurre en este
error, cuando se utiliza un puntero antes de haberlo inicializado. Veamos un
ejemplo:
main() /*Este programa
est incorrecto*/
{
char l, *p;
l='m';
*p=l;
}
El problema en este
programa es que se est asignando 'm' a alguna posición de memoria
desconocida ya que el puntero p nunca fué inicializado. Como consecuencia, el
programa se para . La solución para evitar este tipo de contratiempos es
asegurar siempre que el puntero esté apuntando a alguna dirección v lida
antes de usarlo.
Error en la
utilización de punteros
Este tipo de error se
suscita cuando no se utilizan correctamente los operadores* o &.
main() /*Este programa es erróneo*/
{
int n, *p;
n=10;
p=n;
printf("%d",*p);
}
La llamada a printf()
no imprime el valor de n en la pantalla sino un valor desconocido ya que la
asignación p=x; es incorrecta. Esta sentencia asigna el valor 10 al puntero p,
aquí es donde se comete el error ya que un puntero sólo puede recibir direcciones.
Para corregir el programa se escribir
p=&x.>
El utilizar punteros,
no quiere decir que vayas a tener problemas con ellos en tu programa. De hecho,
cualquier tipo de datos o estructura puede producir errores si no est
bien estructurada tanto sintáctica como lógicamente. Por tanto, sólo hay que
tener cuidado, y asegurarse de saber a donde apunta cada puntero antes de
usarlo.