vector es

12
Vectores, Matrices y Punteros en c++ con 36 comentarios Estimados lectores y fans, les pido disculpas por este humilde y sencillo post, se que este mini-tutorial super básico es una humillación a su inteligencia y profesionalismo, pero comprendan que esto va dedicado a personas que como yo recién empiezan con sus primeros pininos en C++. Espero de verdad le sea útil a alguien. Escribir todo esto, me costó una noche entera y mucho café. Parte de los conceptos aquí los aprendí en clases de la U y mucho también lo aprendí por cuenta propia. Así que agradecimientos al teacher Patricio del cual aprendí muchísimo. Una vez más a ustedes y a los tantos miles de seguidores que me leen a diario las disculpas del caso. Vamos ir avanzando de a pocos así que no se preocupen y desesperen porfavor, paciencia. La idea es que esta sección crezca con su ayuda, feedback y motivación. Luego vamos a ver ejemplos con objetos, clases, sobrecarga de operadores, métodos de búsqueda, màs ordenación, punteros, listas, pilas, colas, templates… por ahora sigo practicando y haciendo simples cosas con este lenguaje. Los códigos los compilé con g++, el compilador de GNU. VECTORES Un vector, también llamado array(arreglo) unidimensional, es una estructura de datos que permite agrupar elementos del mismo tipo y almacenarlos en un solo bloque de memoria juntos, uno despues de otro. A este grupo de elementos se les identifica por un mismo nombre y la posición en la que se encuentran. La primera posición del array es la posición 0. Podríamos agrupar en un array una serie de elementos de tipo enteros, flotantes, caracteres, objetos, etc. Crear un vector en c++ es sencillo, seguimos la siguiente sintaxix: Tipo nombre[tamanyo]; Ejm: 1 int a[5];//Vector de 5 enteros 2 float b[5];//vector de 5 flotantes 3 Producto product[5];//vector de 5 objetos de tipo Producto Podríamos también inicializar el vector en la declaración: 1 int a[] = {5,15,20,25,30}; 2 float b[] = {10.5,20.5,30.5,12.5,50.5} 3 Producto product[] = {celular,calculadora,camara,ipod,usb} Como hay 5 elementos en cada array, automáticamente se le asignará 5 espacios de memoria a cada vector.Pero si trato de crear el vector de la forma int a[]; el compilador

Upload: marcos-palacios

Post on 18-Jan-2016

213 views

Category:

Documents


0 download

DESCRIPTION

qqq

TRANSCRIPT

Page 1: Vector Es

Vectores, Matrices y Punteros en c++

con 36 comentarios

Estimados lectores y fans, les pido disculpas por este humilde y sencillo post, se que este

mini-tutorial super básico es una humillación a su inteligencia y profesionalismo, pero

comprendan que esto va dedicado a personas que como yo recién empiezan con sus

primeros pininos en C++. Espero de verdad le sea útil a alguien.

Escribir todo esto, me costó una noche entera y mucho café. Parte de los conceptos aquí

los aprendí en clases de la U y mucho también lo aprendí por cuenta propia. Así que

agradecimientos al teacher Patricio del cual aprendí muchísimo. Una vez más a ustedes y a

los tantos miles de seguidores que me leen a diario las disculpas del caso.

Vamos ir avanzando de a pocos así que no se preocupen y desesperen porfavor, paciencia.

La idea es que esta sección crezca con su ayuda, feedback y motivación. Luego vamos a

ver ejemplos con objetos, clases, sobrecarga de operadores, métodos de búsqueda, màs

ordenación, punteros, listas, pilas, colas, templates… por ahora sigo practicando y

haciendo simples cosas con este lenguaje. Los códigos los compilé con g++, el

compilador de GNU.

VECTORES

Un vector, también llamado array(arreglo) unidimensional, es una estructura de datos que

permite agrupar elementos del mismo tipo y almacenarlos en un solo bloque de memoria

juntos, uno despues de otro. A este grupo de elementos se les identifica por un mismo

nombre y la posición en la que se encuentran. La primera posición del array es la posición

0.

Podríamos agrupar en un array una serie de elementos de tipo enteros, flotantes,

caracteres, objetos, etc. Crear un vector en c++ es sencillo, seguimos la siguiente

sintaxix: Tipo nombre[tamanyo];

Ejm:

1 int a[5];//Vector de 5 enteros

2 float b[5];//vector de 5 flotantes

3 Producto product[5];//vector de 5 objetos de tipo Producto

Podríamos también inicializar el vector en la declaración:

1 int a[] = {5,15,20,25,30};

2 float b[] = {10.5,20.5,30.5,12.5,50.5}

3 Producto product[] = {celular,calculadora,camara,ipod,usb}

Como hay 5 elementos en cada array, automáticamente se le asignará 5 espacios de

memoria a cada vector.Pero si trato de crear el vector de la forma int a[]; el compilador

Page 2: Vector Es

mostrará un error, porque no indiqué el tamaño del vector ni tampoco inicializé sus

elementos.

Asigno valores a los elementos de un vector indicando su posición:

1 int a[4] = 30; // le asigno el valor 30 a la posición 4 del vector, es decir, al 5to elemento.

2 product[2].setPrecio(300) // le asigno un precio de 300 al producto en

la posicion 2, o sea al tercer elemento.

Obviamente el método setPrecio() debe de estar implementado.

Para llenar, recorrer e imprimir un vector podemos utilizar un bucle for:

01 #include <iostream>

02 using namespace std;

03

04 int main()

05 {

06 int dim;

07 cout << "Ingresa la dimension del vector" << endl;

08 cin >> dim; // Supongamos que ingrese 10

09 int vector[dim]; // mi vector es de tamanyo 10

10

11 for(int i=0;i < dim;i++){

12 vector[i] = i * 10;

13 cout << vector[i] << " ";

14 }

15

16 return 0;

17 }

La salida del programa mostrará: 0 10 20 30 40 50 60 70 80 90

Fàcil verdad? Bien ahora creen 2 o más vectores y empiecen a hacer funciones básicas

como sumar, restar, buscar, ordenar, moda, etc que ayudan mucho a ir desarrollando la

lógica. No vale copiar y pegar, mejor es practicar, practicar y practicar.

Aquí una función simple para sumar 2 vectores a y b y poner el resultado en un tercer

vector c

01 #include <iostream>

02 using namespace std;

03

Page 3: Vector Es

04 void sumar(int a[], int b[], int c[],int dim){

05 for (int i=0; i<dim; i++) {

06 c[i]=a[i] + b[i];

07 }

08 }

09

10 void imprimir(int v[],int dim)

11 {

12 for(int i=0;i<dim;i++){

13 cout << v[i] << " ";

14 }

15 cout << endl << endl;

16 }

17

18 int main()

19 {

20 int dim;

21 cout << "Ingresa la dimension" << endl;

22 cin >> dim;

23

24 int a[dim];

25 int b[dim];

26 int c[dim];

27

28 for(int i=0;i<dim;i++){

29 a[i] = i * 10;

30 b[i] = i * 5;

31 }

32

33 cout << "Vector A " << endl;

34 imprimir(a,dim);

35

36 cout << "Vector B " << endl;

37 imprimir(b,dim);

38

39 sumar(a,b,c,dim);

40 cout << "Vector C " << endl;

41

42 imprimir(c,dim);

Page 4: Vector Es

43 return 0;

44 }

Este programa me botaría (si ingreso una dimensión de 10):

Vector A

0 10 20 30 40 50 60 70 80 90

VECTOR B

0 5 10 15 20 25 30 35 40 45

VECTOR C

0 15 30 45 60 75 90 105 120 135

Entonces para tomar en cuenta:

Todo vector debe tener definido un tipo de dato.

Todo vector necesita de una dimensión o tamanyo.

El código de arriba se puede mejorar muchísimo con objetos y clases, este es solo un

pequeño ejemplo.

MATRICES

Una matriz es un vector de vectores o un también llamado array bidimensional. La manera

de declarar una matriz es c++ es similar a un vector:

1 int matriz[fils][cols];

int es el tipo de dato, matriz es el nombre del todo el conjunto de datos y debo de

especificar el numero de filas y columnas. Las matrices también pueden ser de distintos

tipos de datos como char, float, double,etc.

Las matrices en c++ se almacenan al igual que los vectores en posiciones consecutivas de

memoria. Usualmente uno se hace la idea que una matriz es como un tablero. Pero

internamente el manejo es como su definicion lo indica, un vector de vectores, es decir,

los vectores estan uno detras del otro juntos.

La forma de acceder a los elementos de la matriz es utilizando su nombre e indicando los

2 subindices que van en los corchetes. Si Coloco int matriz[2][3]=10; //estoy asignando al

cuarto elemento de la tercera fila el valor 10. No olvidar que tanto filas como columnas se

enumeran a partir de 0.

Bueno y para recorrer una matriz podemos usar igualmente un bucle. En este caso 2 for

1 for(int i=0;i<fils;i++){

2 for(int j=0;j<cols;j++){

3 matriz[i][j] = i % j;

4 }

5 }

PUNTEROS

El valor de todas las variales que manejamos en nuestros programas se almacenan en

Page 5: Vector Es

memoria y tienen una dirección. Un puntero es una variable especial que apunta a la

dirección de memoria de una variable. El puntero tiene a su vez su propia dirección. Todas

estas direcciones tienen un formato hexadecimal.

Los punteros son herramientas muy poderosas con muchas utilidades y enormes ventajas

como veremos más adelante. A grandes rasgos, un puntero me permite desplazarme en la

memoria, apuntar, redireccionar a ciertas variables, funciones, métodos, objetos sin

necesidad de mover grandes bloques de datos, lo cual nos ahorra muchísimo el consumo

de memoria en los programas.

Un puntero se debe declarar de acuerdo al tipo de dato al que apunta. Ejem:

1 int *var; //Un puntero llamado var que podra apuntar a cualquier variable de tipo entero.

2 char *u;//puntero de tipo char

3 Persona *per;//puntero de tipo persona

Para determinar,asignar la dirección de una variable en c++, se usa el operador & y para

obtener el contenido de un puntero utilizamos el operador * Ejem:

1 int a;//entero

2 int *b;//puntero a entero

3 a = 20;//a tiene 20

4 b=&a;//asigno la direccion de a al puntero b

5

6 cout << b << endl; // imprira la direccion de memoria de a;

7 cout << *b;// imprimira 20, osea el contenido de a

Ahora analicemos las siguientes instrucciones y veamos como las variables van cambiando

de valor en tiempo de ejecución:

01 #include <iostream>

02 using namespace std;

03 int main () {

04 int a=10;

05 int b=20;

06 int *p,*p2;//punteros de tipo entero

07

08 cout << "ANTES" << endl;

09 cout << "Variable a = " << a << endl;

10

11 cout << "Direccion de a = " << &a << endl << endl;

12

Page 6: Vector Es

13 cout << "Variable b = " << b << endl;

14 cout << "Direccion de b = " << &b << endl << endl;

15

16 cout << "Contenido de p (BASURA)= " << *p << endl;//tiene basura al principio, podria inicializar con *p=0

17 cout << "Direccion de p = " << &p << endl << endl;

18

19 cout << "DESPUES" << endl;

20 a++;//incremento a

21 p= &a; //p ahora tiene a la direccion de a

22

23 cout << "Contenido de p = " << *p << endl;

24

25 p = &b;//p ahora tiene la direccion de b

26 *p +=20; // le sumo 20 al contenido de p, es decir, estoy

incrementando el valor de b

27

28 cout << "Variable a = " << a << endl;

29 cout << "Variable b = " << b << endl << endl;

30

31 p=&a;//p ahora tiene la direccion de a

32 *p = a * 5;//contenido de p es igual al contenido de a * 5

33

34 cout << "Contenido de p = " << *p << endl;

35 cout << "Variable a = " << a << endl << endl;

36

37 cout << "Contenido de p2 (BASURA) = " << *p2 << endl;//tiene basura al principio, podria inicializar con *p2=0

38 cout << "Direccion de p2 = " << &p2 << endl << endl;

39

40 p2 = p;//el contenido de p es asignado al contenido de p2

41 *p2 +=15;//incremento 15 al contenido de p2

42

43 cout << "Contenido de p2 = " << *p2 << endl;//igual al contenido de p

44 p++;//p apunta a otra direccion de memoria,se desplaza 4 bytes en

memoria

45 cout << "Contenido de p (BASURA) = " << *p << endl;//el contenido de esa nueva direccion

46

Page 7: Vector Es

47 return 0;

48 }

La salida del programa:

ANTES

Variable a = 10

Direccion de a = 0x22ff74

Variable b = 2

Direccion de b = 0x22ff70

Contenido de p (BASURA)= -1017291943

Direccion de p = 0x22ff6c

DESPUES

Contenido de p = 11

Variable a = 11

Variable b = 40

Contenido de p = 55

Variable a = 55

Contenido de p2 (BASURA) = 2293680

Direccion de p2 = 0x22ff68

Contenido de p2 = 70

Contenido de p (BASURA) = 2293680

El contenido de p y p2 al principio es basura porque no tienen ningun valor asignado aun.

Podriamos asignar el valor NULL a un puntero para luego posteriormente en algun

problema que se me presente saber el estado del puntero y saber si contiene algo o no,

así:

int *p= NULL;

ARITMÉTICA DE PUNTEROS

En las ultimas sentencias del programa anterior:

p++;

cout << *p;

Pueden visualizar que estoy incrementando el puntero p en 1. Esto quiere decir que el

puntero se desplazara 4 bytes en memoria (en este caso por ser entero) y entonces

apuntara a otra direccion. Por eso es que el nuevo contenido de p es basura o bueno el

contenido de lo que tiene esa nueva direccion a la que apunta.

Supongamos que definir un entero y puntero de tipo char:

1 char c;

2 char *d;

3

Page 8: Vector Es

4 d= &c;//asigno la direccion de c a d

5 c='u';//asigno el valor u a mi variable c

6 c--;//desplazo una posicion a c

7 cout << *d;//

No Imprimira ‘u’ porque fijense que desplazé c en sentido negativo 1 byte (los char

ocupan a 1 byte). Es decir, que si d estaba apuntado a una direccion como por ejemplo

0x22ff99, despues del c– estara apuntando a algo como 0x22ff98

Para tomar en cuenta cosas que no puedo hacer con punteros:

01 int a=15;

02 int *p;

03

04 double *q;

05 void *r;

06

07 p = a; //No puedo hacer esto porque estoy asignando una variable a un

puntero y un puntero es una direccion.

08 p = &50; // 50 es un valor constante en este caso y no una variable,por

lo tanto no tiene direccion

09 p = &(a+1); //una expresion no tiene direccion

10 p = 30;//igual que el primer error, 30 es un entero.

11 &a = p;//no puedo cambiar la direccion de una variable

12 p = q;//p es puntero de tipo entero y q de tipo double

Un puntero de tipo void, es un puntero al cual le podemos asignar cualquier tipo de

puntero. Por lo tanto si podriamos hacer esto:

r = p;

VECTORES Y PUNTEROS

Cuando declaramos un vector int v[10];El nombre del vector, o sea v, es un puntero al

primer elemento del vector, es decir a v[0].Entonces como un vector es un puntero al

primer elemento del mismo, también podríamos hacer aritmética de punteros con el

vector.

1 (v+1) ;//apuntara a v[1];

2 *(v+5);//me refiero al contenido de v[5]

3

4 //Y también a los punteros les puedo poner índices:

5

6 int *p; //puntero de tipo entero

7 p = &v[0];//p apunta a la direccion del vector v[0] o tambien a v. p =

v

8 p[8] = 80; //le asigno el valor 80 al puntero en la posicion 8, es decir

Page 9: Vector Es

a v[8]

VECTORES DINÁMICOS

Lo que vimos en el inicio de este post, son vectores estáticos, puesto que tienen una

cantidad fija de memoria asignada y tamaño definido que no podemos modificarlo. Sin

embargo, un vector podría tener una cantidad variable de datos, a este se le llama un

vector dinámico.

Para usar vectores dinámicos necesitamos gestionar memoria dinámica. Si bien es cierto

que es trae enormes ventajas, el hacer un mal uso de la memoria dinámica nos podría

traer problemas desastrozos. Por eso es importante que que cuando creemos vectores

dinámicos también liberemos la memoria utilizada. Obviamente eliminaremos la memoria

utilizada cuando ya no necesitamos más usar, en este caso, un determinadao vector.

El operador new sirve para reservar memoria dinámica.

El operador delete se usa para liberar la memoria dinámica reservada con new.

Para liberar memoria de un array dinámico usamos delete[]

El espacio de memoria que hemos reservado con new tendrá vida hasta que finalize la

ejecución del programa o cuando liberemos ese espacio con delete. Siempre es

recomendable liberar memoria para posteriormente no tener problemas con excesivo

consumo de memoria.

Un simple ejem:

01 #include <iostream>

02 using namespace std;

03

04 int main()

05 {

06 int *pv;

07 int dim;

08

09 cout << "Ingresa el tamanyo del vector" << endl;

10 cin >>dim;

11 pv = new int[dim];

12

13 for(int i=0;i<dim;i++){

14 pv[i] = i * i;

15 cout << pv[i] << " ";

16 }

17

18 delete[] pv;

Page 10: Vector Es

19 return 0;

20 }

MATRICES Y PUNTEROS

Supongamos que se declaró una matriz int m[5][5]

Como dijimos anteriormente, el nombre o identificador de un vector es un puntero al

primer elemento del vector. En el caso de matrices el nombre de la matriz, en este

ejemplo v, es un puntero que apunta al primer elemento del primer vector de la matriz.

Entonces m es un doble puntero.m es igual a &m[0] que es igual a la direccion de

&m[0][0].

Si declaramos un puntero int *pm y luego igualamos pm = m, p ahora puede desplazarse

por los valores de m.

*p;//contenido de m[0],el cual apunta al primer elemento de ese vector, es decir, m[0][0]

También puedo referirme a los contenidos con aritmética de punteros

1 *(p+1);//Desplazo una posicion a p,se refiere al contenido de m[1],el

cual apunta al primer elemento de ese vector, es decir, m[1][0]

2 *(*(p+1)+1);//desplazo una posición en el vector principal y este a su

vez se desplaza una posicion en ese vector. es decir,me refiero al

contenido de m[1][1];

3

4 p[2][4] = 20;//asigno el valor 20 a la posicion 2,4 de la matriz

5 *(*(p+2)+4) = 20 // es lo mismo que la asignacion anterior

6 *(pm[2]+4) = 20 // tambien los mismo

7

8 //En conclusión:

9 p[i][j] = *(*(p+i)+j) = *(pm[i]+j)

MATRICES DINÁMICAS

Para crear una matriz dinámica debemos de crear un doble puntero int **pm y samos al

igual que los vectores el operador new para reservar memoria y delete para liberar.

Primero tenemos que crear el vector que contendrá a otros vectores especificando el

numero de vectores que tendra este vector principal. Ejem:

1 pm = new int* [fils];//creo el vector de punteros principal

2 for(int i=0;i<fils;i++){

3 pm[i] = new int [cols];//para crear los vectores dentro del vector principal

4 }

Page 11: Vector Es

Ahora sí vamos al grano y veamos un simple programa que crea una matriz dinámica,

asigna valores, muestra el contenido de cada uno de los elementos los elementos así

como sus direcciones de memoria.

También mostramos la matriz usando aritmética de punteros,ahí va:

01 #include <iostream>

02 using namespace std;

03

04 int main()

05 {

06 int **pm;//puntero a una matriz

07 int fils,cols;

08

09 cout << "Ingresa el nro de filas: ";

10 cin >>fils;

11

12 cout << endl;

13 cout << "Ingresa el nro de columnas: ";

14 cin >>cols;

15

16 pm = new int* [fils];

17 for(int i=0;i<fils;i++){

18 pm[i] = new int [cols];

19 }

20

21 cout << "Elementos de la Matriz con sus direcciones" << endl;

22 for(int i=0;i<fils;i++){

23 for(int j=0;j<cols;j++){

24 pm[i][j] = i + j;

25 cout << pm[i][j] << "--> ";

26 cout << &pm[i][j] << " ";

27 }

28 cout << endl;

29 }

30 cout << endl;

31

32 cout << "La matriz con aritmetica de punteros" << endl;

33 for(int i=0;i<fils;i++){

34 for(int j=0;j<cols;j++){

Page 12: Vector Es

35 *(*(pm+i)+j) = i + j;//aritmetica de punteros

36 cout << *(*(pm+i)+j) << "-->";

37 cout << &pm[i][j] << " ";

38 }

39 cout << endl;

40 }

41

42 for(int i=0;i<fils;i++){

43 delete[] pm[i];//elimino cada vector de la matriz

44 }

45 delete[] pm;//elimino el vector principal

46 return 0;

47 }

La salida del programa:

Ingresa el nro de filas: 6

Ingresa el nro de columnas: 4

01 //Elementos de la Matriz con sus direcciones

02 0–> 0×3d2c90 1–> 0×3d2c94 2–> 0×3d2c98 3–> 0×3d2c9c

03 1–> 0×3d2ca8 2–> 0×3d2cac 3–> 0×3d2cb0 4–> 0×3d2cb4

04 2–> 0×3d2cc0 3–> 0×3d2cc4 4–> 0×3d2cc8 5–> 0×3d2ccc

05 3–> 0×3d3ab8 4–> 0×3d3abc 5–> 0×3d3ac0 6–> 0×3d3ac4

06 4–> 0×3d3ad0 5–> 0×3d3ad4 6–> 0×3d3ad8 7–> 0×3d3adc

07 5–> 0×3d3ae8 6–> 0×3d3aec 7–> 0×3d3af0 8–> 0×3d3af4

08

09 //La matriz con aritmetica de punteros

10 0–> 0×3d2c90 1–> 0×3d2c94 2–> 0×3d2c98 3–> 0×3d2c9c

11 1–> 0×3d2ca8 2–> 0×3d2cac 3–> 0×3d2cb0 4–> 0×3d2cb4

12 2–> 0×3d2cc0 3–> 0×3d2cc4 4–> 0×3d2cc8 5–> 0×3d2ccc

13 3–> 0×3d3ab8 4–> 0×3d3abc 5–> 0×3d3ac0 6–> 0×3d3ac4

14 4–> 0×3d3ad0 5–> 0×3d3ad4 6–> 0×3d3ad8 7–> 0×3d3adc

En mi caso esa son las direcciones de memoria. Bueno ya que hemos revisado conceptos

básicos a continuación veamos la Clase Matriz, su definición, algunos métodos y su

implementación.