Tutorial Cpp
PROGRAMACIÓN ESTRUCTURADA
Estructura del Código en C++.
Los archivos que se van a crear, van a tener la exención C, .cc, .cpp, .CPP, .c++, .cp, o .cxx, y tendrán la siguiente estructura básica:
1 . #include <iostream> 2 . using namespace std; 3 . 4 . // This is a tradition 5 . 6 . int main() /* you can comment like this to*/ 7 . { 8 . cout << "Hello World\n"; // Print 'Hello Word' 9 . return 0; 10 . } 11 . 12 . /* The general form is: 13 . * int main (int argc, char *argv[] , other_parameters ) { body } 14 . * argc - Non-negative value representing the number of arguments passed 15 . * to the program from the environment in which the program is run. 16 . * argv - Pointer to the first element of an array of pointers to 17 . * null-terminated multibyte strings that represent the arguments 18 . * passed to the program from the execution environment (argv[0] 19 . * through argv[argc-1]). The value of argv[argc] is guaranteed to be 0. 20 . * body - The body of the main function 21 . * 22 . */
y se guardará en helloworld.cpp.
NOTA: En caso de usar el compilador GCC, y dejarlo escoger el lenguaje automáticamente, entonces los archivos .C son C++, mientras que .c son de C.
Temas sugeridos
- Identificadores (nombres de variables).
- Tipos de variables.
- Palabras reservadas en C++.
- Uso del ";".
Compilado básico.
Primero se chequea que se tenga un compilador gcc (lo usual es que si). En la consola se escribe lo siguiente
g++ -v
y el resultado debe algo parecido a esto
Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper Target: x86_64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Debian 5.3.1-8' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --with-arch-32=i586 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu Thread model: posix gcc version 5.3.1 20160205 (Debian 5.3.1-8)
Ahora, se va a compilar el código que guardamos en el archivo helloword.cpp, y en la consola se escribe:
g++ helloworld.cpp -o helloworld.out
Aquí el compilador es g++, y la opción -o es para decir el nombre del archivo de salida .out (ejecutable), Y este se puede ejecutar por medio de la consola así:
./programa.out
Por el momento esto es todo lo que se va a necesitar del compilador, mas adelante se volverá sobre este asunto.
Operadores.
Un operador le dice al compilador que realice una manipulación determinada. En C++ se puede dividir en seis grupos.
- Operadores Aritméticos.
Como su nombre lo indica realizan operaciones aritméticas básicas sobre las variables numéricas. Suponiendo que a las variables X e Y se les asigna los valores de 6 y 4- Suma +
- Resta -
- Multiplicación *
- División /
- Modulo %
- Incremento ++
- Decremento --
Ejemplo:Al compilar este código, y ejecutarlo muestra el resultado de aplicar cada uno de los operadores aritméticos.#include <iostream> using namespace std; main() { int a = 21; int b = 10; int c ; cout << "a=" << a << endl ; cout << "b=" << b << endl ; c = a + b; cout << "a+b=" << c << endl ; c = a - b; cout << "a-b=" << c << endl ; c = a * b; cout << "a*b=" << c << endl ; c = a / b; cout << "a/b=" << c << endl ; c = a % b; cout << "a%b=" << c << endl ; c = a++; cout << "a++=" << c << endl ; c = a--; cout << "a--=" << c << endl ; return 0; }
- Operadores Relacionales.
Estos operadores realizan comparaciones entre las variables y resultan en valores lógicos (TRUE o FALSE).- Igual que ==
- Diferente que !=
- Mayor que >
- Menor que <
- Mayor o igual que >=
- Menor o igual que <=
Ejemplo:Este codigo cuando se compila y se ejecuta recibe dos enteros y los usa para ilustrar el uso de los operadores relacionales.#include <iostream> #include <stdio.h> #include <stdlib.h> using namespace std; main(int argc, char *argv[]) { bool c; cout << "el valor 0 equivale a FALSE, y 1 a TRUE" << endl ; if(argc != 3) { fprintf(stdout,"Ingreso %d argumentos, el número de argumentos es 2\n",argc); return 1; }//endif int a = atoi(argv[1]); int b = atoi(argv[2]); cout << "a=" << a << endl; cout << "b=" << b << endl; c = (a == b); cout << "a == b es:" << c << endl ; c= ( a < b ); cout << "a < b es:"<< c << endl ; c= ( a > b ); cout << "a > b es:"<< c << endl ; c= ( a <= b ); cout << "a <= b es:"<< c << endl ; c= ( b >= a ); cout << "b >= a es:"<< c << endl ; return 0; }
- Operadores Lógicos
Estos operadores actúan sobre las variables lógicas, y tienen como resultado valores lógicos- Disyunción &&
- Conjunción ||
- Negación !
Ejemplo:#include <iostream> #include <stdio.h> #include <stdlib.h> using namespace std; main(int argc, char *argv[]) { if(argc != 3) { fprintf(stdout,"Ingreso %d argumentos, el número de argumentos es 2\n",argc); return 1; }//endif bool a = atoi(argv[1]); /*si es diferente de cero es uno*/ bool b = atoi(argv[2]); cout << "a=" << a<< endl; cout << "b=" << b<< endl; if ( a && b ) { cout << "a && b es TRUE" << endl; }else { cout << "a && b es FALSE" << endl; } if ( a || b ) { cout << "a || b es TRUE" << endl; }else { cout << "a || b es FALSE" << endl; } if ( !(a && b) ) { cout << "!(a && b) es TRUE" << endl; }else { cout << "!(a && b) es FALSE" << endl; } if ( !(a || b) ) { cout << "!(a || b) es TRUE" << endl; }else { cout << "!(a || b) es FALSE" << endl; } return 0; }
- Operadores bit a bit
Estos operadores realizan acciones sobre las variables bit a bit- Disyunción binaria &
- Conjunción binaria |
- Complemento binario ~
- Desplazamiento binario a derecha >>
- Desplazamiento binario a izquierda <<
Ejemplo:#include <iostream> /*cin,cout*/ #include <stdio.h> /*fprintf */ #include <stdlib.h> /* strtol */ #include <string.h> /* strcat */ using namespace std; /*Creamos una función para convertir los numeros a su forma binaria*/ const char *byte_to_binary(int x) { static char b[64]; b[0] = '\0'; int z; for (z = 1024; z > 0; z >>= 1) { if ((x & z) == z) strcat(b,"1"); else strcat(b,"0"); } return b; } int main(int argc, char *argv[]) { if(argc != 3) { cout << "Ingreso" << argc << "argumentos, el número de argumentos es 2"<< endl; return 1; }//endif int a = atoi(argv[1]); int b = atoi(argv[2]); int c; if((a>=1024| b>=1024)) { cout << "Alguno de los argumentos,es mayor que 1024"<< endl; return 1; }//endif printf ("a= %d\n",a); printf ("binario: a= %s\n",byte_to_binary(a)); printf ("b= %d\n",b); printf ("binario b=: %s\n",byte_to_binary(b)); c = a & b; printf ("a & b= %d\n",c); printf ("binario a & b=: %s\n",byte_to_binary(c)); c = a | b; printf ("a | b= %d\n",c); printf ("binario a | b=: %s\n",byte_to_binary(c)); c = a ^ b; printf ("a ^ b= %d\n",c); printf ("binario a ^ b=: %s\n",byte_to_binary(c)); c = ~a; printf ("~a= %d\n",c); printf ("binario ~a=: %s\n",byte_to_binary(c)); c = a << 2; printf ("a << 2= %d\n",c); printf ("binario a << 2=: %s\n",byte_to_binary(c)); c = a >> 2; printf ("a >> 2= %d\n",c); printf ("binario a >> 2=: %s\n",byte_to_binary(c)); return 0; }
Cuando se compila y ejecuta este código se obtieneusuario@debian:/C++/Ejemplos$ ./operador_bitwise.out 11 12 a= 11 binario: a= 00000001011 b= 12 binario b=: 00000001100 a & b= 8 binario a & b=: 00000001000 a | b= 15 binario a | b=: 00000001111 a ^ b= 7 binario a ^ b=: 00000000111 ~a= -12 binario ~a=: 11111110100 a << 2= 44 binario a << 2=: 00000101100 a >> 2= 2 binario a >> 2=: 00000000010
- Operadores de Asignación
Estos operadores asignan los valores de las variables- Asignación =
- Operación y Asignación OP=
Ejemplo:#include <iostream> /*cin,cout*/ #include <stdlib.h> /* atoi */ using namespace std; int main(int argc, char *argv[]) { if(argc != 3) { cout << "Ingreso" << argc << "argumentos, el número de argumentos es 2"<< endl; return 1; }//endif int a = atoi(argv[1]); int b = atoi(argv[2]); int c; cout << "a= " <<a<< endl ; cout << "b= " <<a<< endl ; c = a; cout << "Operador c = a : entonces c= " <<c<< endl ; c += a; cout << "Operador c -+= : entonces c= " <<c<< endl ; c -= a; cout << "Operador c -= : entonces c= " <<c<< endl ; c *= a; cout << "Operador c *= : entonces c= " <<c<< endl ; c /= a; cout << "Operador c /= : entonces c= " <<c<< endl ; c = b; cout << "Operador c = b : entonces c= " <<c<< endl ; c %= a; cout << "Operador c %= : entonces c= " <<c<< endl ; c <<= 2; cout << "Operador c <<= : entonces c= " <<c<< endl ; c >>= 2; cout << "Operador c >>= : entonces c= " <<c<< endl ; c &= 2; cout << "Operador c &= : entonces c= " <<c<< endl ; c ^= 2; cout << "Operador c ^= : entonces c= " <<c<< endl ; c |= 2; cout << "Operador c |= : entonces c= " <<c<< endl ; return 0; }//End_main
- Otros Operadores
Éstos operadores no pueden ser clasificados en uno de los anteriores grupos- sizeof
- Condición ? X : Y
- ,
- .
- ->
- & a un puntero puntero
- * a un puntero puntero
Ejemplo 1:Ejemplo 2 Punteros:#include <iostream> #include <string> using namespace std; int main() { int ch=sizeof(char) ; int in=sizeof(int) ; int si=sizeof(short int); int li=sizeof(long int) ; int fl=sizeof(float) ; int du=sizeof(double) ; int wc=sizeof(wchar_t) ; cout << "tamaño de una variable en bytes : " << endl; cout << endl; cout << "tamaño de una variable tipo char : " << ch << endl; cout << "tamaño de una variable tipo int : " << in << endl; cout << "tamaño de una variable tipo short int : " << si << endl; cout << "tamaño de una variable tipo long int : " << li << endl; cout << "tamaño de una variable tipo float : " << fl << endl; cout << "tamaño de una variable tipo double : " << du << endl; cout << "tamaño de una variable tipo wchar_t : " << wc << endl; int bch=ch*8; int bin=in*8; int bsi=si*8; int bli=li*8; int bfl=fl*8; int bdu=du*8; int bwc=wc*8; cout << endl << endl; cout << "tamaño de una variable en bits : " << endl; cout << endl; cout << "tamaño de una variable tipo char : " << bch << endl; cout << "tamaño de una variable tipo int : " << bin << endl; cout << "tamaño de una variable tipo short int : " << bsi << endl; cout << "tamaño de una variable tipo long int : " << bli << endl; cout << "tamaño de una variable tipo float : " << bfl << endl; cout << "tamaño de una variable tipo double : " << bdu << endl; cout << "tamaño de una variable tipo wchar_t : " << bwc << endl; cout << endl << endl; string flag; //esto es nuevo!! y depende de la librería string cout << "Uso operador 'condition? X:Y': " << endl << endl; flag= (ch > li) ? "Yes":"No" ; cout << "(char > long int)? " << flag <<endl<< endl<< endl; int var=0; int a=100; cout << "Uso operador 'coma': " << endl<< endl; cout << "Valor inicial var= "<< var << " ,Valor inicial a= "<< a << endl; var = (a--, a+10, a*2); cout << "var = (a--, a+10, a*2)" << endl; cout << "Valor final var= " <<var<< endl; cout << endl << endl; int c; float b=2.342345; cout << "Uso operador 'cast': " << endl<< endl; cout << "b= "<< b << endl; c = (int) b; cout << "(int)b = " << c << endl<< endl ; return 0; }
#include <iostream> using namespace std; int main () { int var; int *ptr; // en ptr se guarda direcciones de memoria int val; var = 3000; ptr = &var; val = *ptr; cout << "var = 3000" << endl; cout << "var = " << var << endl; cout << "ptr = &var" << endl; cout << "ptr = " << ptr << endl; cout << "val = *ptr" << endl; cout << "val = " << val << endl; return 0; }
Decisiones.
Ya se ha usado anteriormente, en varios ejemplos. A continuación la sintaxis de los diferentes tipos de decisions:if
if(expresión lógica) { // Instrucciones que se ejecutan para el caso en que expresión lógica = TRUE }
if...else
if(expresión lógica) { // Instrucciones que se ejecutan para el caso en que expresión lógica = TRUE } else { // Instrucciones que se ejecutan para el caso en que expresión lógica = FALSE }
switch
switch(expresión){ case valor-1 : Comandos; break; //Opcional case valor-2 : Comandos; break; //Opcional . . . case valor-n : Comandos; break; //Opcional // Se pueden tener los casos que se quieran. default : //Opcional Comandos; }
Loops.
Los loops o bucles, se utilizan cuando es necesario ejecutar cierta parte (o partes) del código un número determinado de veces. A continuación se listan
varios tipos de bucles en C++
whileloop
Ejecuta un grupo de sentencias mientras la condición sea verdadera, dicha condición se evalúa antes de comenzar el loop. La estructura esy la sintaxis básica en C++ es la siguiente:
while(condition) { statement(s); }
donde condition es una expresión que se interpreta como verdadero cualquier valor diferente de cero, y cero como falso.
Ejemplo:
#include <iostream> using std::cout; using std::endl; int main () { int i = 20; // while loop execution while( i > 1 ) { cout << "i= " << i << endl; i=i-1; } return 0; }
for loop
Ejecuta una secuencia de sentencias un determinado número de veces. La estructura esy la sintaxis en C++ se muestra a continuación
for ( init; condition; increment ) { statement(s); }
Ejemplo
#include <iostream> int main () { for( int i = 20; i > 1; i-- ) { std::cout << "i= " << i << std::endl; } return 0; }
do ... while loop
Como su nombre lo indica, realiza una tarea mientras la condición sea verdadera, se debe de tener en cuenta que la condición se evalúa al final de cada iteración. su estructura es la siguienteEjemplo:
{CODE(colors="cpp")}#include <iostream> using std::cout; using std::endl; int main () { int i = 20; // while loop execution while( i > 1 ) { cout << "i= " << i << endl; i=i-1; } return 0; }{CODE}
Comandos de Control de loops.
Modifican la manera en como se recorre el loop- break: Para el loop, sin importar si se alcanzó o no la condición de parada. La ejecución sigue fuera del loop (diferente de return).
Sintaxis:break;
- continue: Hace que el la ejecución salte el resto del contenido del loop, y continua después de chequear la condición del loop.
Sintaxis:continue;
- goto: Hace un salto hacia donde este la etiqueta (label)
Sintaxis:goto label; .. . label: statement;
Ejemplo:#include <iostream> /*cin,cout*/ #include <stdlib.h> /* strtol */ using namespace std; int main(int argc, char *argv[]) { if(argc != 2) { cout << "Ingreso" << argc << "argumentos, el número de argumentos es un entero"<< endl; return 1; }//endif int a = atoi(argv[1]); int i=0; cout << "Número elegido:" << a << endl; COMP:for( ; ; )//esto es un loop infinito //COMP es la etiqueta para el goto { i++; cout << "Número de loop:" << i << endl; cout << "Número:" << a << endl; if (a>0) { cout << "a=" << a <<" ,Número mayor que cero (uso continue)" << endl; a=a-1; continue; }else if (a==0) { cout << "a=" << a <<" ,Número igual a cero (uso breake)" << endl; break; }else if (a<0) { cout << "a=" << a <<" ,Numero menor que cero (uso goto)" << endl; a++; goto COMP; }else { cout << "Error en el cast" << endl; return 1; } } return 0; }
Funciones.
Tipo Nombre( lista de parámetros ) { Cuerpo de la función }
Donde:
- Tipo: Cual es el tipo de dato que devuelve la función i.e. char, int, double, etc.
- Nombre: Nombre con el cual se va a llamar la función.
- Parámetros: Entradas de la function de la forma Tipo Nombre
- Cuerpo: Lo que hace propiamente la función.
Ejemplo:
#include <stdio.h> /* printf */ #include <string.h> /* strcat */ #include <stdlib.h> /* strtol */ // Este codigo convierte enteros en binarios menores de 2^10 const char *byte_to_binary(int x) //Función tipo puntero a char, y tiene un entero como parámetro { static char b[64]; b[0] = '\0'; int z; for (z = 1024; z > 0; z >>= 1)// 1024 es 2^10 un 1 y 10 ceros en binario { // z>>= mueve el numero bit por bit a la derecha if ((x & z) == z) // compara (x&z) con z (ver tabla de &) strcat(b,"1"); else strcat(b, "0" ); } return b; // devuelve el vector de char } int main(void) { /* byte to binary string */ printf("%s\n", byte_to_binary(250)); return 0; }
Arreglos.
Un arreglo en C++ es una secuencia ordenada de elementos de un tipo, que se organizan consecutivamente en la memoria.
Declarando un arreglo e inicializando
Hay una declarar un arreglo (por el momento estático) en C++tipo Nombre [ tamaño ];
Donde:
- tipo: tipo de las variables del arreglo.
- Nombre: Nombre con el que se llama al arreglo
- tamaño: cual es el número de elementos del arreglo (>0)
y varias formas de inicializarlas
double arreglo[5] = {200.2, 26.1, 30.24, 12.0, 20.0}; double arreglo[] = {200.2, 26.1, 30.24, 12.0, 20.0}; double otro[5]; otro[0] =200.2; otro[1] =26.1; otro[2] =30.24; otro[3] =12.0; otro[3] =20.0;
todas estas formas crean exactamente el mismo tipo de arreglo. En la última forma asigna los elementos de manera individual, es bueno tener en cuenta que los indices de los arreglos en C++ comienzan en cero (0).
Ejemplo:
#include <iostream> using std::cout; using std::endl; #include <iomanip> using std::setw;//esta funcion genera espacios en el output #include <stdlib.h> /*atoi*/ int main(int argc, char *argv[]) { if(argc != 2) { cout << "Ingreso" << argc << "argumentos, el número de argumentos es 1"<< endl; return 1; }//endif int n = atoi(argv[1]); int m[ 10 ]; // se declara el arreglo // se inicializa el arreglo usando un for for ( int i = 0; i < 10; i++ ) { m[ i ] = i* n; } cout << "La Tabla de multiplicar del número " << n << endl; cout << "Número" << setw( 13 ) << "Valor" << endl; // output each array element's value for ( int j = 0; j < 10; j++ ) { cout << setw( 4 )<< j << setw( 13 ) << m[ j ] << endl; } return 0; }
Arreglos multidimensionales
De forma similar a los de una dimensión se declaran
tipo Nombre[Tamaño1][Tamaño2]...[TamañoN];
Ejemplo:
#include <iostream> using namespace std; int main () { // Declaramos e inicializamos una matriz de 4X3 de enteros, llamada a. int a[4][3] = { {0,0,0}, {1,2,3}, {2,4,6}, {3,6,9}}; // Ahora se muestran en pantalla for ( int i = 0; i < 4; i++ ) for ( int j = 0; j < 3; j++ ) { cout << "a[" << i << "][" << j << "]: "; cout << a[i][j]<< endl; } return 0; }
Uso de punteros en arreglos
Cuando se declara un arreglo, lo que se hace es declarar un puntero constante al primer elemento del arreglo, así si se declara el arreglo double vector[10] ;, entonces vector es un puntero constante a la dirección de memoria &vector[0]Así se pueden usar nombres de arreglos como punteros constantes, o viceversa. luego es lo mismo vector[4] (que es el nombre del arreglo), que usar la dirección en memoria *(vector +4) (que toma la posición de memoria *vector y la aumenta en 4).
Ejemplo:
#include <iostream> using namespace std; int main () { double vector[4] = {10,20,30,40}; double *p; p = vector; cout << "muestro los valores arreglos " << endl; for ( int i = 0; i < 4; i++ ) { cout << "vector[" << i << "]= "; cout << vector[i] << endl; } cout << "muestro los valores usando punteros " << endl; for ( int i = 0; i < 4; i++ ) { cout << "*(p + " << i << ") : "; cout << *(p + i) << endl; } cout << "Muestro los valores usando el nombre como dirección " << endl; for ( int i = 0; i < 4; i++ ) { cout << "*(vector + " << i << ") : "; cout << *(vector + i) << endl; } return 0; }
Pasar un arreglo como argumento de una función
Hay tres maneras de pasar un arreglo como argumento a una función:
- Arreglo definido:
tipo_funcion nombre_funcion(tipo_arreglo nombre_arreglo[tamaño_arreglo]) { . }
- Arreglo indefinido:
tipo_funcion nombre_funcion(tipo_arreglo nombre_arreglo[]) { . }
- puntero al arreglo:
tipo_funcion nombre_funcion(tipo_arreglo *nombre_arreglo) { . }
Funciones que entregan arreglos
Si se quiere que una función devuelva arreglos, se debe de declarar de la siguiente manera
tipo_funcion * nombre_funcion() { . }
Strings.
Los strings en C son arreglos de chars, que terminan con el símbolo null (\0), y pueden ser asignados de dos formas
char saludo[5] = {'H', 'o', 'l', 'a','\0'};
char saludo[] = "Hola";
luego en C++ es posible usar todas las herramientas de C para el manejo de estos elementos, se sugiere que se estudien las siguientes funciones de C para el manejo de chars
- strcpy
- strcat
- strlen
- strcmp
- strchr
- strstr
Strings en C++
En C++, la librería estándar posee una clase (luego se hablará de esto), que permite mucha mas libertad en la manipulación de cadenas de caracteres o strings, solo vasta con incluir la librería <string>.Ejemplo
#include <iostream> #include <string> //llamo la librería using namespace std; int main () { string str1 = "Hola"; string str2 = "Mundo"; string str3, str4; int len ; //se igualan a los valores str3= " "; // guardo un espacio en str3 // se pueden concatenar las cadenas de caracteres str4 = str1 + str3 + str2; cout << "str1 + str3 + str2 : " << str4 << endl; // las funciones asociadas al objeto str4 se llaman con el operador . len = str4.size(); cout << "tamaño" << endl; cout << "str4.size() : " << len << endl; return 0; }
Punteros.
Sabemos que las variables almacenan diferentes tipos de datos en posiciones bien definidas de la memoria. Estas direcciones pueden se pueden ver usando el operador & como se vio anteriormente.
Ya se ha usado el concepto de puntero, pero para ser mas preciso se intentará hacer una definición:
Puntero: Es una variable cuyo valor es la dirección en memoria de otra variable. La forma en que se declara es
tipo *nombre;
Aunque el tipo de variable que guarda el puntero siempre es el mismo (hexadecimal), la diferencia es el tipo de variable a la que el puntero apunta.
Las acciones que se realizan sobre los punteros son las siguientes:
- Declarar.
- Asignar.
- Acceder.
Ejemplo:
#include <iostream> using namespace std; int main () { int var = 20; int *ip; // Declaración de variable tipo puntero a entero ip = &var; // Asignación de valor del puntero //Muestro el valor almacenado en var cout << "Valor de variable var: " << var << endl; //Muestro la dirección de memoria de var que está guardada en ip cout << "Dirección de memoria guardada en ip: " << ip << endl; //Acceso a la valor almacenado en var a través del puntero cout << "Valor de *ip: " << *ip << endl; //Tambien puedo mostrar la dirección de memoria del puntero cout << "Dirección de memoria de ip, &ip : " << &ip << endl; return 0; }
Punteros a NULL
Por buena práctica de programación es habitual en el momento de declarar un puntero se le asigna por defecto el valor de NULL, i.e que no apunta a ningun lado (aunque realmente apunte a la dirección 0). Esto se usa para evitar dejar en un programa punteros sin asignar.Ejemplo:
#include <iostream> #include <stdlib.h> /*atoi*/ using namespace std; int main(int argc, char *argv[]) { int *ptr = NULL; if(argc >=2) { int a = atoi(argv[1]); ptr = &a; } //endif if(!ptr) { cout << "Puntero a NULL"<< endl ; //si trata de acceder a *ptr, Segmentation fault!!! } if(ptr) { cout << "Asignado, con valor:" << *ptr << endl; } return 0; }
Aritmética de punteros
Como un puntero es una variable que contiene una dirección en memoria, que en últimas es un número (hexadecimal), luego sobre este número se pueden realizar operaciones algebraicas. Las operaciones permitidas sobre los puntero son cuatro: ++, --, - y + . Además pueden ser comparados por medio de ==,<=,>=, < y >.Ejemplo:
#include <iostream> using namespace std; const int MAX = 4; int main () { int var[MAX] = {1, 3, 5,7}; int *ptr; ptr = var; //asigna la dirección del primer elemento de var a ptr (ojo var es un arreglo) int i = 0; while ( ptr <= &var[MAX - 1] ) /* compara la direccion en ptr con la del último elemento del arreglo var, para parar el ciclo*/ { cout << "Dirección de var[" << i << "]: " << ptr << endl; cout << "Valor de var[" << i << "]= " << *ptr << endl; ptr++;// Aumento el puntero en una pocición (memoria contigua) i++; } return 0; }
Arreglos de punteros
Siguiendo la lógica de los arreglos, un arreglo de punteros se declara asítipo *nombre[tamaño];
Ejemplo:
#include <iostream> using namespace std; #include <iomanip> using std::setw; const int MAX = 5; int main () { //recordando que un string es una cadena de caracteres, caracterizada por un puntero const char *nombres[] = {"Camilo","Omar","Abdul","Alejo","Alephys"}; cout << "Número" << setw( 10 ) << "Nombre" << setw( 15 )<< "Direccion" << endl; for (int i = 0; i < MAX; i++) { cout << setw( 4 ) << i << setw( 12 ) << nombres[i] << setw( 17 ); cout << &nombres[i] <<endl; } return 0; }
Puntero a puntero
Es un puntero que guarda la dirección de memoria de un puntero que a su vez guarda la dirección de memoria de una variable, se declara así:
tipo**var;
Ejemplo:
#include <iostream> using namespace std; int main () { int var; int *ptr; int **pptr; var = 3000; // La dirección de var se guarda en ptr ptr = &var; // La direccion de ptr se guarda en pptr pptr = &ptr; // Accediendo al valor a través de la variable, puntero y puntero a puntero. cout << "var= " << var << endl; cout << "*ptr= " << *ptr << endl; cout << "**pptr= " << **pptr << endl; cout << "Direcciones de memoria" << endl; cout << "&var= " << &var << endl; cout << "ptr= " << ptr << endl; cout << "*pptr= " << *pptr << endl; cout << "pptr= " << pptr << endl; cout << "&pptr= " << &pptr << endl; return 0; }
Pasando un puntero como argumento
Para pasar a una función un puntero (dirección en memoria), simplemente en la declaración de los parámetros de la función el puntero.Ejemplo:
#include <iostream> using namespace std; // Declaramos la funcion, encuentra el numero mayor del arreglo double mayor(double *arr, int tamano); int main () { // double arreglo[] = {1,2,15,8,2}; double M; // Se pasa el puntero a la funcion como argumento. M = mayor( arreglo, 5 ) ; // output the returned value cout << "El número mayor es: " << M << endl; return 0; } //Funciones double mayor(double *arr, int tamano) { double may; may=arr[0]; //le asigno el primer elemento for (int i = 1; i < tamano; ++i) { if ( may < arr[i]) { may = arr[i]; }//end if }//end for return may; }
Funciones que devuelven puntero
De manera similar a como se declara una función que devuelve un tipo definido de dato, se puede hacer que la función devuelva un puntero (dirección de memoria), declarándola así
tipo* nombre(argumentos) { . }
Es buena idea declarar la variable que se va a devolver como estática, pues de otro modo en el momento en que termine la ejecución del programa, la memoria de las variables locales es liberada.
Ejemplo: Ver ejemplo de Funciones, y compilar el código con y sin static en la función byte_to_binary.
Referencias.
C++ I/O.
Estructuras.
Depuración (gdb, valgrind).
PROGRAMACIÓN BASADA EN OBJETOS
Clases y Objetos.
- Clase es una estructura abstracta de datos que contiene atributos y metodos- Objecto es la instancia de una clase, es cuando declaro una variable del tipo de la clase.
- Atributos son las variables de las clases
- métodos son las "funciones" de la clase
Herencia.
- es tomar todas las propiedades de una clase(Clase base) y pasarlas a una nueva clase(Clase hija).Sobrecarga de operadores
- es hacer que una clase pueda usar los operadores definidos en c++, con procedimientos definidos dentro de la clase.Polimorfismo.
- sobrecargar metodosAbstracción.
Encapsulacion.
es darle acceso a los datos en tres niveles- public: el objecto puede acceder
- protected: la clase puede acceder desde la herencia
- private: solo se accede en la clase.
ejemplos.
posicion.h
#ifndef POS_H #define POS_H namespace mylib { class posicion { public: posicion():x(0),y(0),z(0){} posicion(double _x,double _y,double _z)//constructor { x=_x; y=_y; z=_z; } void setPosicion(double _x,double _y,double _z)//metodo setter { x=_x; y=_y; z=_z; } //metodos getter double getX(){return x;} double getY(){return y;} double getZ(){return z;} //sobre carga de operador = posicion &operator=(posicion &pos); double distancia(posicion &pos); protected: double x,y,z; }; } #endif
posicion.cxx
#include<posicion.h> #include<cmath> using namespace mylib; posicion &posicion::operator=(posicion &pos) { this->x=pos.x; this->y=pos.y; this->z=pos.z; return *this; } double posicion::distancia(posicion &pos) { return sqrt(pow(x-pos.x,2)+pow(y-pos.y,2)+pow(z-pos.z,2)); }
main.cxx
#include<posicion.h> #include<iostream> int main() { mylib::posicion p1(0,0,0); mylib::posicion p2(1,1,1); std::cout<<"distancia entre dos puntos = "<<p1.distancia(p2)<<std::endl; return 0; }
Makefile
CXXFLAGS=-I. main: posicion.cxx posicion.h main.cxx $(CXX) $(CXXFLAGS) $< $@.cxx -o $@