Informática
C++
-+Introducción al Lenguaje C++
Qué necesito para correr C++?.
Un computador IBM PC AT o compatible.
MS-DOS 3.31 o una versión posterior.
Un ratón compatible con Microsoft.
Monitor EGA, VGA o mayor resolución.
Por lo menos 8 Megabytes libres en disco duro.
Historia.
El lenguaje C nació en el laboratorio telefonico de la compañia AT&T en 1972, este fue creado por Dennis Ritchie, quien en ese entonces utilizaba C como soporte del Sistema operativo UNIX para las primeras maquinas DEC PDP-11.
AT&T lo enserio como un compilador (comp. C) llamado K&R C que junto con el sistema operativo UNIX empezaron a invadir universidades. Despues, cada persona que adquiria una copia de UNIX recibia un compilador de C gratis. El lenguaje mas popular fue C. Por lo tanto UNIX fue escrito en C. Entonces si ud. queria entender UNIX ud. tenia que aprender C. La caracteristica era que C era gratis y entonces nadie se sentia presionado a aprenderlo. Cual fue el resultado?, un gran estandar.
Luego C se convirtio en un gran estandar, entonces las compañias introducian sus propios compiladores C. Incluyendo que pudiesen ejecutarse en otros sistemas operativos que no fuesen UNIX. Cada uno de estos compiladores introducia ensanchamientos diseñados para mejorar las limitaciones que mostraba el modelo original. Pero las modificaciones que cada quien hacia traia como resultado la incompatibilidad de las versiones entre si, entonces incrementaba la demanda por un estandar a nivel nacional. Entonces en 1987 nacio el primer estandar "The American National Standars Institute (ANSI) version of C" esta version fue mejor conocida como ANSI C o C estandar. C++ esta basado en estos compiladores y por lo tanto es el mas compatible con ANSI C.
C++ como lenguaje orientado a objeto.
En la decada de 1970 se volvió popular el concepto de objeto entre los investigadores de los lenguajes de programación. Un objeto es un conjunto de codigos, datos diseñados para emular o imitar una entidad fisica o abstracta. Los objetos son eficientes como elementos de programación por dos razones principales: representan una abstracción directa de los elementos que se utilizan comunmente y ocultan la mayor parte de la complejidadde su implantación a los usuarios. Los primeros objetos que se desarrollaron fueron aquellos que estaban más intimamente ligados a las computadoras, como INTERGER, ARRAY y STACK. Ademas se diseñaron lenguajes como el SmallTalk el cual es ya ortodoxo, donde se definia todo como un objeto.
Variables y Tipos de Datos.
Una de las confusiones a la hora de programar por primera vez en C es: La declaración de los diferentes tipos de objetos.
Todas las variables deben ser declaradas antes de ser utilizadas de acuerdo al orden establecido para su tipo. El tipo puede ser uno definido por el usuario o uno de los que pone a disposición el lenguaje. Los tipos basicos son:
Tipo | Significado | Memoria Requerida |
char | Caracter | 1 byte |
int | Entero | 2 bytes |
float | Punto flotante de presición simple | 4 bytes |
double | Punto flotante de presición doble | 8 bytes |
Un ejemplo tipico de declaraciones validas es el siguiente:
int i; /* por defecto es signed */
char c; /* por defecto es signed */
unsigned char uc;
long int li;
unsigned short int si;
signed long sl; /* El tipo entero (int) es asumido */
Existen para una mayor flexibilidad en la declaración de las variables, los modificadores de tipos:
unsigned: Para convertir cualquier tipo de dato numerico con rango en ambos signos solamente en uno solo, es decir los positivos.
TIPO Longitud Rango .
unsigned char 8 bits 0 a 255
unsigned int 16 bits 0 a 65535
unsigned long 32 bits 0 a 4.294.967.295
En oposición a este tipo de datos existe el signed.
short / long : Acorta / Alarga la capacidad de una variable numerica.
ej:
TIPO Longitud Rango .
short int 8 bits 0 a 255
int 16 bits
long int 32 bits
long double 80 bits
Como declarar una variable.
Principalmente se deben cumplir tres reglas:
La sintaxis es: <tipo de la var.> <nombre de la var.>;
El nombre se escribe de manera única: "Tam" es diferente a "tam".
Algunos identificadores se utilizan como "palabras reservadas" y no se pueden utilizar como nombres de variables.
Las declaraciones son validas desde la linea n hasta el fin de la función o en caso de ser globales, durante todo el programa.
Arreglos.
Son una colección de datos accesados por medio de un indice.
declaración:
arreglo unidimiensional o vector:
<tipo var.> <nombre var.> [T];
ej: int vector[10];
arreglo bidimensional o matriz:
<tipo var.> <nombre var.> [T1] [T2];
ej: char matriz [5] [5];
arreglo n-dimensional:
<tipo var.> <nombre var.> [T1] [T2]...[Tn];
El rango de acceso al vector siempre va desde 0 (cero) hasta (Tn - 1).
Punteros en C++
Declaración y uso de punteros simples:
Un puntero es una variable que contiene una dirección de memoria, usualmente la dirección de otra variable. Considerese el siguiente ejemplo:
void fn( )
{
int i;
int *pI;
pI = &i; /* pI ahora apunta a i */
*pI = 10; /* asignamos 10 a i */
}
Las variables tipo puntero son normalmente declaradas como cualquier otra variable, excepto por la adición del caracter unario * (asterisco). En una expresión, el unario & significa "La dirección de" y el unario * significa "La dirección que apunta ó Contenido de". Entonces se pudiese leer la primera instrucción como "asigne la dirección de i en pI". La segunda asignación es "asigne 10 en la dirección que apunta pI".
Veamos que sucede en memoria:
Fig. 1 asignando la dirección de i en pI:
pI = &i;
0x100 | ||
i | 0x102 | |
0x104 | ||
pI | 0x102 | 0x106 |
0x108 | ||
0x10A |
Fig. 2 asignando 10 en la dirección que apunta pI:
*pI = 10;
0x100 | ||
i | 10 | 0x102 |
0x104 | ||
pI | 0x102 | 0x106 |
0x108 | ||
0x10A |
Es importante siempre conservar los tipos de las variables en las asignaciones que se hagan manejando punteros, fijese a aca siempre se conservo el tipo ENTERO.
El tipo puntero char* cumple el papel de un tipo cadena aparte. Cualquier cadena de caracteres entre comillas dobles se asume como un tipo char*. En adición a los caracteres que ud. copie, C añade el caracter 0 (cero), el cual es usado como fin de cadena. Este fin de cadena es conveniente porque es facil verificar un 0 en cualquier estructura de repetición (recuerdese que el 0 es falso).
Por ejemplo considerese la siguiente función, la cual hace que todos los caracteres en una cadena pasen a ser mayuscula.
#include <ctype.h>
void upperCase(char *pS)
{
while (*pS)
{
if (islower(*pS))
{
*pS = toupper(*pS);
}
pS++;
}
}
void fn( )
{
char *pString;
pString = "Estructura";
upperCase(pString);
}
En la función fn( ), la asignación que se le hace a pString es permitida porque tanto pString como "Estructura" son del tipo char *. El valor de la subexpresión "Estructura" es la dirección de la cadena compuesta por 'E' 's' 't' 'r' 'u' 'c' 't' 'u' 'r' 'a' y termina con '\0'.
Las variables tipo apuntador son aquellas que guardan la dirección de un valor que se encuentra almacenado en memoria.
Operaciones sobre punteros.
En el ejemplo anterior podemos notar la instrucción pS++ en la funcion upperCase. De aca podemor inferir que algunos de los operadores comunes implementados para los tipos de datos conocidos tambien sirven para los tipo punteros. Pero tambien debemos fijar diferencias con respecto a lo que se pueda representar:
void main(void)
{
int i = 5;
int pI = &i;
int b;
b = 2 * *pI
}
*pI es un entero. (es el entero apuntado por pI). Como cualquier otro entro *pI esta sujeto a las operaciones definidas para cuelaquier otro entero. Entonces, aparte de *, cuales otros operadores estan definidos para pI propiamente.
Incremento de los punteros.
Nosotros ya conocemos que el operador ++ esta definido para los punteros. Para ver los resultados del incremento de una variable puntero, vamos a mostrar un ejemplo grafico. Vamos tambien a asumir que la cadena "Estructura" esta asignada al comienzo de la posición 0x100, un solo caracter por byte y que pS apunta al principio de esta cadena.
pS++
pS Antes | E | 0x100 |
pS Despues | s | 0x101 |
t | 0x102 | |
r | 0x103 | |
u | 0x104 | |
c | 0x105 | |
t | 0x106 | |
u | 0x107 | |
r | 0x108 | |
a | 0x109 | |
\0 | 0x10A |
Los diseñadores de C pensaron que esta manera de diseño fue realmente pulcra. Pero, que pasa si se requiere mas de un byte para el tipo de dato?, o que pasa si PS apunta a algo distinto que una cadena de caracteres como un arreglo de enteros, en el cual cada uno de los elementos toma 2 bytes en un PC?. Entonces la adición (++) no trabajaria bien porque 0x101 no correspondería a la dirección precisa.
Los inventores de C hicieron una regla que sigue dejando a la adición como una función pulcra pero con una ligera trampa, para todos los tipos. Siempre que aquellos tomen más de 1 byte: La adición a una variable puntero esta siempre definida en terminos del tamaño de la cosa a quien apunta.
Por ejemplo, si pS apunta a un entero de 2-bytes, pS++ añadirá 2 a pS en vez de 1. Si pS apuntara a alguna estructura compleja, pS++ pudiera añadir 50 bytes al valor de pS. Dicho de otra forma, si pS es la dirección de la casa (house), pS++ mueve pS a la siguiente casa (house), abajo en el bloque, respectivamente al tamaño del bloque.
Ej. Tipo Entero almacenado en memoria:
DIRECCION: 1489 |
890 |
Declaración:
int *ap_n;
<tipo_variable> *<nombre_puntero>;
Desde el momento en que sedeclara de esta manera solo tenemos una variable vacia, ahora, como llenamos esta variable?
Podemos llenarla de dos formas:
1. Teniendo una variable existente por medio de una declaración previa:
ej:
#include <stdio.h>
void main()
{
float f;
float *pF;
pF=&a;
*pF=178.2;
printf("%f",f);
}
2) Apartando memoria directamente con la función MALLOC.
ej:
#include <alloc.h>
void main()
{
int *pt_int;
pt_int=(int *)malloc(sizeof(int));
*a=34;
free(pt_int);
}
NOTA: Una vez apartada la memoria siempre debe tenerse en cuenta que, despues de utilizarla se debe devolver al sistema porque de lo contrario llenariamos toda la memoria y produciriamos un desborde (o error).
Arreglos y Punteros.
Hay una relación directa entre adiciones a un puntero y la indexación de un arreglo. Considerese cual es el significado de indexar dentro de un arreglo de enteros.
void fn(int i)
{
int array[10];
int *pI;
array[i] = 0; /* asigna 0 en el i-esimo elemento */
pI = &array[0];
*(pI + i) = 0; /* tiene el mismo efecto que el anterior */
}
array[x] es interpretado como *(array + x).
Pasando apuntadores a funciones.
Los argumentos de una función en C simepre son pases por valor. Esto es, que cuando la llamada es hecha, solo el valor de la variable es pasada.
Considerese el siguiente ejemplo:
void fn(int i)
{ i = 10; } /* el valor de i es 10 */
int main()
{ int i = 0;
fn(i); /* solo el 0 es pasado a fn( ) */
return 0; }
Si usted busca cambiar el valor de la variable llamando a una función, usted debe pasar la dirección de la variable.
void fn(int *pI)
{ *pI = 10; }
int main()
{ int i = 0;
fn(&i); /* ahora el valor de i es 10*/
return 0; }
En caso de pasar un arreglo seria:
void zero(int i, int *pArray)
{ pArray[i]=0; }
int main()
{int array[100];
zero(10, array);
return 0;}
Tipos definidos por el usuario.
Una estructura es definida y accesada, de la siguiente manera:
struct Registro
{
int primerElem;
float segundoElem;
}
void fn()
{
struct Registo reg;
reg.primerElem=0; /* se refiere al miembro entero */
reg.segundoElem=1.0; /* se refiere al miembro real */
}
Uno necesita diferenciar entre una estructura y una instancia de una estructura (una instancia de una estructura es tambien conocida como un objeto). En el ejemplo anterior, la estructura es Registro y el objeto es reg. Un ejemplo mas tangible seria: Lector es una CLASE de gente quienes leen libros, y ud. es una instancia de CLASE LECTOR.
Los arreglos y los registros pueden ser mezclados. Ud. puede tener un arreglo de estructuras, como se demuestra con ms en el siguiente ejemplo.
struct Registro
{
float unElemento;
int unArreglo[10];
};
void fn()
{
struct Registro arrReg[20];
arrReg[10].unElemento=10.0;
arrReg[10].unArreglo[5]=5;
}
Los registros tambien pueden ser inicializados de la siguiente manera:
struct Registro
{
int primerElem;
float segundoElem;
};
void fn()
{
struct Registro simple = {1, 2.0};
struct Registro array[2] = { {1, 2.0}, /* array[0] */
{2,4.4}}; /* array[1] */
}
Punteros a Estructuras en C.
En el siguiente ejemplo se muestra como declarar un puntero a un objeto estructura.
struct Registro
{
int primerElem;
float segundoElem;
};
void fn()
{
struct Registro reg1;
struct Registro *pREG;
pREG = ®1; /* pREG apunta al objeto reg1 */
pREG->primerElem = 1; /* referencia al primer elemento
del objeto apuntado por pREG */
pREG->segundoElem = 2.0; /* you get the idea */
}
El tipo de pREG es struct Registro *, el operador -> es usado para accesar los miembro de estructuras apuntadas por un tipo puntero.
pREG->primerElem es equivalente a (*pREG).primerElem
Operaciones sobre punteros a estructuras.
Los mismos operadores que estan definidos para los punteros, tambien estan definidos para los punteros a estructuras definidas por los usuarios, por ejemplo:
struct Registro
{
char *pName;
/* y cualquier otra cosa */
};
void fn(int number, struct Registro *pREG)
{
while (number > 0) /* loop until count exhausted */
{
pREG->pName = (char *)0;
number --;
pREG++; /* go to next element in array */
}
}
Como la adición esta definida sobre punteros a estructuras, el operador de índice [] esta también definido, entonces el ejemplo anterior también pudo ser escrito.
void fn(int number, struct Registro *pArray)
{
int i;
for (i=0; i < number; i++)
{
pArray[i].pName = (char *)0;
}
}
Usando punteros a estructuras
Los punteros a estructuras consiguen su principal aplicación en las listas. Los objetos, Intrínsicamente no tienen como los enteros o los reales (floats) no tienen manera de apuntar a otro objeto, es por ello que que necesario crear un arreglo para tener referenciado a cada uno de ellos. Muchas veces los arreglos son inconvenientes para muchas de nuestra aplicaciones, se hace difícil insertar o eliminar un valor en medio del arreglo.
Los objetos estructuras pueden incluir punteros a otras estructuras, incluso a ella misma. En el siguiente ejemplo tenemos una pequeña implementación de listas.
struct Llist
{
/* se incluyen los datos que ud. quiera */
int loquesea;
struct Llist *prox; /* puntero al prox.objeto en lista */
};
struct Llist *primero; /* puntero al primero de la lista */
Un recorrido por la lista se pudiera hacer de la siguiente manera:
void fn()
{
struct Llist *pLL;
/* comienza con el primero; continua hasta
que pLL es 0; pasa de elemento en elemento cada loop */
for (pLL = primero; pLL; pLL=pLL->proximo)
{
if (pLL->loquesea == 0)
{
/* ...whatever processing you want here... */
}
}
}
El tipo void
El tipo de dato void, en ocaciones significa nada; osea cuando no pasamos o recibimos nada de una función, decimos que devuelve o enviamos void.
Además el tipo void, es un tipo extremadamente util que se toma como cualquier tipo de puntero a una variable, es decir, se puede decirle que se comporte como cualquiera de los tipos punteros establecidos por el C.
ejemplo:
#include <stdio.h>
main()
{
void *g; /* puntero a void (a cualquier tipo) */
int a=6, *p;
g=&a; /* g contiene una dirección pero no se sabe
de que tipo */
*(int *)g=4; /* vea la direccion de g como la de un
entero y asignele 4 */
p=(int *)g; /* asigne a p la dir. de g que es un entero */
*p=5; /* asignación normal de un entero */
printf("Codigo de 2 bytes en memoria: %c%c",*(char *)g,*((char *)(g+1)));
}
Asignación correcta de valores.
Enteros:
Una constante entera es un numero con un valor entero, consistente en una secuencia de dígitos. Las constantes enteras se pueden escribir en tres sistemas numericos diferentes: decimal (base 10), octal (base 8) y hexadecimal (base 16).
Un ejemplo de c/u se incluye a continuación:
Decimales: 0 1 743 37467
Octales: 0 01 0343 05777
Hexadecimal 0x 0x1 0X7FFf 0xabcd
Enteros Largos y Sin signo:
Constante Sistema de Numeración
50000U decimal (sin signo)
123456789L decimal (larga)
123456789UL decimal (larga sin signo)
0123456L octal (larga)
0777777U octal (sin signo)
0x50000U hexadecimal (sin signo)
0xFFFFFUL hexadecimal (larga sin signo)
Coma flotante:
0. 1. 0.2 827.602
50000. 0.000743 12.3 315.323
2E-8 0.006e-3 1.6667E+8 0.121212e12
Archivos
Muchas aplicaciones requieren leer información de un periférico auxiliar de almacenamiento. Tal información se almacena en el periférico en la forma de un archivo de datos. Por lo tanto, los archivos de datos permiten almacenar información de modo permanente, para ser accedida o alterada cuando sea necesario.
En C existe existen un conjunto extenso de funciones de biblioteca para crear y procesar archivos de datos. A diferencia de otros lenguajes de programación, en C no se distingue entre archivos secuenciales y de acceso directo (acceso aleatorio). Pero existen dos tipos distintos de archivos de datos, llamados archivos secuenciales de datos (o estandar) y archivos orientados a sistema (o de bajo nivel). Generalmente es más fácil trabajar con archivos de datos secuenciales que con los orientados a sistema.
Apertura y Cierre de un archivo:
Cuando se trabaja con archivos secuenciales de datos, el primer paso es establecer un area de buffer, donde la información se almacena temporalmente mientras se está transfiriendo entre la memoria de la computadora y el archivo de datos. Este buffer permite leer y escribir información del archivo más rapidamente de lo que sería posible de otra manera. El area de buffer se establece escribiendo:
FILE *ptvar;
donde FILE (se requieren letras mayusculas) es un tipo especial de estructura que establece el area de buffer y ptvar la variable puntero indica el inicio de esta área. El tipo de estructura de FILE está definido en el sistema de archivos include, tipicamente en stdio.h. El puntero ptvar se refiere a menudo a un archivo secuencial.
Para abrir un archivo se utiliza la funcion de biblioteca fopen. Se escribe como:
ptvar = fopen(nombre_archivo, tipo_archivo);
donde nombre_archivo y tipo_archivo son cadenas que presentan, respectivamente, el nombre del archivo y la manera en la que el archivo será utilizado. El nombre_archivo debe ser consistente con la manera en que se nombran los archivos en el sistema operativo utilizado, y tipo_archivo está compuesto por una o varias de las cadenas que aparecen en la siguiente tabla:
Tipo_Archivo | Significado |
"r" | Abrir un archivo existente solo para lectura. |
"w" | Abrir un nuevo solo para escritura. Si existe un archivo con el nombre_archivo especificado, será destruido y creado uno nuevo en su lugar. |
"a" | Abrir un archivo existente para añadir (añadir información nueva al final del archivo). Se creará un archivo nuevo si no existe un archivo con el nombre nombre_archivo especificado. |
"r+" | Abre un archivo existente para lectura y escritura. |
"w+" | Abre un archivo nuevo para lectura y escritura. Si existe un archivo con el nombre_archivo especificado, será destruido y creado uno nuevo en su lugar. |
"a+" | Abrir un archivo existente para leer y añadir. Se creará un archivo nuevo si no existe un archivo con el nombre nombre_archivo especificado. |
Se retorna un valor NULL si no se puede abrir el archivo, por ejemplo si un archivo existente no se encuentra.
Finalmente un archivo de datos debe cerrarse al final del programa. Esto puede realizarce con la función de biblioteca fclose, aunque la mayoria de los compiladores de C cerrarán automaticamente todos los archivos de una sesión.
#include <stdio.h>
FILE *fpt;
fpt = fopen("muestra.dat", "w");
...
fclose(fpt);
Crear un Archivo de Datos:
#include <stdio.h>
/* leer una linea de texto en minusculas y almacenarla
en mayusculas */
main()
{
FILE *fpt;
char c;
/* abrir un archivo nuevo solo para escritura */
fpt = fopen("muestra.dat","w");
/* lee un caracter y escribe su mayuscula equivalente
en el archivo */
do
putc(toupper(c = getchar()), fpt);
while (c != '\n');
fclose(fpt);
}
Leer un Archivo de Datos:
#include <stdio.h>
/* leer una linea de texto y mostrarla en pantalla */
main()
{
FILE *fpt;
char c;
/* abrir un archivo nuevo solo para lectura */
if ((fpt = fopen("muestra.dat","r")) == NULL)
printf("\n ERROR - No se puede abrir el archivo
indicado\n");
else
do
putchar(c = getc(fpt));
while (c != '\n');
fclose(fpt);
}
Clases
El Tipo Cadena
Todo puntero declarado de la siguiente manera se inicia en NULO (NULL):
char *pt;
La inicialización de un puntero con un determinado valor da lugar a una dirección de memoria la cual es asignada al puntero correspondiente. Esta inicialización debe ser hecha con comillas dobles, con el fin de indicar que se desea alojar en memoria la frase X. Lo anteriormente descrito solo sucede al usar el tipo "caracter".
Ej:
char *pt;
pt="Laboratorio";
si preguntamos por &pt sera 00CE.
si preguntamos por *pt sera el primer caracter de la frase.
podemos imprimir el valor del puntero pt desde printf y conocer la dirección
Toda frase termina con un caracter que lo indica. El caracter que indica fin de frase es el caracter 0 de la tabla ASCII (\0), el C++ asigna el fin de cadena automaticamente cuando asi se requiera. En el siguiente ejemplo el C++ asigna automaticamente \0 despues de la frase:
char texto[] = "California";
en memoria:
C | a | l | i | f | o | r | n | i | a | \0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
char *ptt = "Alguna frase";
char t[20] = {'c', 'a', 's', 'a'}
printf: imprime una cadena alojada en memoria y apuntada por un apuntador X mediante el siguiente algoritmo: Imprimase el caracter siguiente mientras no se consiga el fin de cadena (\0), al consegirlo, pare.
Headers o Encabezados.
Son librerias que contienen las funciones que vamos a usar en el programa. Por lo general se colocan al principio del programa.
formato:
#include <nombre_func.h>
Librerias mas comunes en C++.
stdio.h, conio.h, iostream.h, string.h, ctype.h, etc.
Funciones más utilizadas en C++.
printf, scanf, malloc, free, cin, cout
Secuencias de escape que actuan como caracteres:
secuencia | Accion realizada por la Comp. |
\a | Alarma |
\b | retroceso |
\f | avance de pagina |
\n | nueva linea |
\r | retorno al carro |
\t | tabulacion horizontal |
\v | tabulacion vertical |
\\ | backslash |
\' | comilla simple |
\" | comilla doble |
Operadores en C++ utilizados comunmente:
Operador | Función |
( ) | llamada a función |
[ ] | subíndice de un arreglo |
. | punto. acceso a miembro de una estructura. |
-> | Flecha. Apunta a miembro " " " |
! | Inversor Lógico |
- | Resta |
-- | Decrementar en uno |
++ | Incrementar en uno |
& | Obtener la dirección de memoria |
* | Obtiene la indirección (contenido de) |
/ | division |
% | modulo (resto de la division) |
+ | suma |
< | menor que |
> | mayor que |
<= | menor igual |
>= | mayor igual |
== | igualdad de comparacion |
!= | desigualdad |
&& | operador logico AND |
|| | operador logico OR |
?: | condicional evalua dos expresiones |
= | asignacion |
, | separador de variables, constantes y expresiones dentro de funciones, estructuras de control, etc. |
sizeof | determina el tamaño de una variable o una estructura. |
Un pequeño programa interesante de analizar es el siguiente:
void fn()
{
int z;
int x=5;
int y=5;
z = ++x; /* el valor de z es 6 */
z = y++; /* el valor de z es 5 */
}
Operadores de Asignación:
Operador | Significado |
*= | multiplicado por |
/= | dividido por |
%= | modulo de |
+= | añadir a |
-= | sustraer desde |
Miscelaneos:
El operador terciario es por lo general confundido con una estructura de control. Este trabaja de la siguiente manera:
a ? b : c;
Si a es verdadero el resultado del operador es el valor de b, sino el resultado es el valor de c, a tambien puede ser una condición o alguna otra estructura que genere verdadero o falso.
Constantes
Como siempre se ha definido en cualquier otro lenguaje las constantes son datos que siempre van a conservar el mismo valor durante todo el programa.
Para la declaración de las constantes comunes utilizaremos:
const int radioTierra = 3959; // en millas
const float radioTierraEnKm = 1.609 * radioTierra;
Debemos hacer incapie en lo que son las constante en toda su extensión, en el siguiente ejemplo a lo mejor no queda tan claro el uso de constantes:
int main()
{
const char * pCC = "Esto es una cadena constante"
char * const cPc = "Esto es un puntero constante"
*pCC='a'; /* ilegal porque es una cadena
constante */
*cPc='a'; // legal
pCC="otra cadena"; // legal
cPc="otra cadena"; // ilegal
return 0;
}
La regla es const se aplicara directamente a la cosa que se encuentre inmediatamente a su derecha.
Existen otro tipo de constantes, que son las definidas, que se utilizan para suplir un extenso codigo:
#define <nemonico> <funcion>
por ejemplo:
#define peso 1.645
#define imprima(a) printf("%i:",a);
#define color(x,y) textcolor(x); textbackground(y);
Sentencias de Control.
break | break; | for (n=1; n<=100; ++n) { scanf("%f", &x); if (x<0) { printf("ERROR- Valor negativo"); break; } ... } |
continue | continue; | for (n=1; n<=100; ++n) { scanf("%f", &x); if (x<0) { printf("ERROR- Valor negativo"); continue; } ... } |
do-while | do sentencia while (expresión) | do printf("%d\n", digito++); while(digito <=9 ); |
for | for(exp1;exp2;exp3) sentencia | for (digito=0; digito<=9; ++digito) printf("%d\n", digito); for (x=0, y=0; x < y; x+=10, y-=10) |
goto | goto etiqueta; etiqueta: sentencia | if (x < 0) goto indicador; ... indicador: printf("ERROR"); |
if | if (expresion) sentencia | if (x < 0) printf("%f",x); |
if-else | if (expresion) sentencia 1 else sentencia 2 | if (estado == 'S') tasa=0.20*paga; else tasa=0.14*paga; |
return | return expresion | return (n1 + n2); |
switch | switch (expresion) { case expresion 1: sentencia 1 sentencia 2 ... sentencia m; break; case expresion 2: sentencia 1 sentencia 2 ... sentencia n break; ... default: sentencia 1 sentencia 2 ... sentencia k } | switch (eleccion = getchar()) { case 'R': printf("ROJO"); break; case 'B': printf("BLANCO"); break; case 'A': printf("AZUL"); break; default: printf("ERROR"); } |
while | while (expresion) sentencia | while (digito<=9) printf("%d\n", digito++); |
ESTRUCTURAS:
2. Definida: La cual representa la definición de un tipo de dato creado por el usuario, aunque la estructura anterior también representa un tipo de dato definido, la diferencia radica en que la "definida" puede ser pasada por parámetro o encabezar los requerimientos de una función mientras que la otra no.
sintaxis:
typedef struct nombre1 {
variable 1;
...
variable n;
} NOMBRE1;
NOMBRE1: es el utilizado para hacer posteriores declaraciones.
CUERPO DEL PROGRAMA.
El programa esta compuesto de la siguiente manera:
funcion 1;
funcion 2;
...
función n;
main o funcion principal;
Donde existe una prelación, es decir la funcion n-1 accesa todas las funciones menos la función n, asi la unica función que puede disponer de todas las demás es la función principal o main.
Toda función excepto el main debe retornar un valor, en caso de que no se retorna nada puede declararse de tipo void (cualquier tipo).
sintaxis:
<tipo_retorno> <nombre_función> (param 1, param 2, ..., param n) {
}
la función main debe declararse de la siguiente forma:
main( ) { }
Esta función será la primera en ejecutarse.
NOTAS:
- No se pueden declarar funciones dentro de otras funciones.
- Las palabras reservadas deben ir en minusculas.
Declaración de funciones.
Una declaración de una función establece tanto el numero y el tipo de argumentos como el tipo del valor retornado. Una función declarada con ningún código se le denomina prototipo de función.
Es un buen estilo de programación el declarar siempre los prototipos de las funciones y antes de usarlas. Esto hace ue el compilador al compilar compare y verifique los tipos de envio y retorno.
Casi siempre los prototipos de las funciones se encuentran almacenados en archivos .h los cuales se incluyende manera muy facil en los programas de C.
Ejemplo:
/* declaración de un prototipo en multiplic.h */
int multiplicar (int PrimerArg, int SegundoArg);
Y para el codigo multiplic.c:
#include "multiplic.h"
/* esta sera la definicion de la funcion */
int multiplicar (int PrimerArg, int SegundoArg)
{
int result;
result = PrinerArg*SegundoArg;
return result;
}
Entonces ahora otros programas podran accesar de manera facil la función multiplicar y ademas el compilador verificará los tipos mas rapidamente aun.
#include "multiply.h"
int OtraFuncion (int a, int b)
{
/* otro codigo */
return multiplicar(a, b); /* el compilador compara esta
llamada con el prototipo */
}
Tambien podemos agregar que si una función no retorna ningun valor o no tiene parametros de entrada puede utilizar el tipo void. Ejemplo:
void noRetorna(int x, int y);
int noArgumentos(void);
void Ninguno(void);
Si ud. no retorna un tipo especifico, entonces C asume el tipo entero (int).
retornaEntero(void);
void noEspecificoArgumento();
Demostración completa de una función:
#include <stdio.h>
#define PI 3.14159
main()
{
float radio, area; /* declaración de variables */
float procesar(float radio); /* declaración de función */
printf("Radio = ?");
scanf("%f", &radio);
area = procesar(radio);
printf("Area = %f",area);
}
float procesar(float r) /* definición de función */
{
float a; /* declaración de variable local */
a = PI * r * r;
return a;
}
HERENCIA:
Se refiere a tomar una clase e instanciarla directamente en sus programas o bien utilizarla como base de una nueva clase que hereda algunas de o todas sus características. Derivando una clase de una clase de base, ud. efectivamente reutiliza el codigo de la clase base para satisfacer sus necesidades.
Cuando se deriva una clase de una clase base, todos los nombres de la clase base se vuelven automáticamente "private" en la clase derivada.
Los especificadotes de acceso para la clase base son los siguientes:
private: es el especificador definido si no se especifica ninguno cuando se declara una clase. Todos las funciones heredables son private en la clase derivada.
public: todos los nombres public de la clase base son public en la clase derivada.
Ej:
CLASS COLA : LISTA { }; // AMBOS SON IDENTICOS
CLASS COLA : PRIVATE LISTA { };
CLASS COLA : PUBLIC LISTA { };
Argumentos que se transmiten a una clase DE BASE:
Para esto se pueden hacer constructures "inline" y "no inline"
TRANSMISION DE PARAMETROS:
ej:
class First {
int a, b, c;
public:
First(int x, int y, int z) {a=x; b=y; c=z}
};
class Second: public First {
int value;
public:
Second(int d) : First(d, d+1, d+5) { value = d; }
Second(int d, int e);
};
// CUERPO DE Second
Second::Second(int d, int e) : First(d, e, 13)
{
value = d + e;
}
OPERADORES "NEW y DELETE":
El operador "new" es similar en funcion al malloc(); pero es un operador, no una funcion. El operador es parte del lenguaje C++ mismo, como lo es el "delete", de modo que no se necesitan incluir archivos de encabezados para utilizarlo. Una de las caracteristicas mas atractivas del operador "new" es que nunca se necesita conversion forzada de tipos. Es decir si se necesitan almacenar 10 elementos en un arreglo de enteros se hace:
int *ip;
ip = new int [10];
int *ip = new int [10];
Sintaxis:
<puntero> = new <tipo> [ long_arreglo ] ( valor_inicial )
una aplicacion de "new" es:
int n;
char *s;
...
cin >> n;
s = new char[n];
nota: si no hay memoria disponible el operador new devuelve 0 es
decir el valor nulo (NULL).
Ventaja del NEW:
NEW HACE QUE SE LLAME A UN CONSTRUCTOR PARA EL OBJETO ASIGNADO Y MALLOC() NO PUEDE.
Descargar
Enviado por: | Wakko |
Idioma: | castellano |
País: | México |