Punteros

Arreglos

Paso de arreglos y punteros como parámetros.

                   
Paso de Arreglos como Parametros

Para pasar arreglos como parámetros debemos recordar que con arreglos no existe el paso por valor como existía en las variables individuales, solo se puede pasar por referencia(dirección)lo que quiere decir que todas las modificaciones que se hagan dentro del arreglo afectaran también a la variable original
Para pasar un arreglo completo como parametro a un procedimiento a una función solo se manda el nombre del arreglo sin corchetes e indices, en el procedimiento o función que recibe solo se declara un arreglo del mismo tipo y se puede usar el mismo o diferente nombre del arreglo.
Entonces tenemos 2 maneras:
void func(int a[]);
void func(int a[5]); 

Ejemplo:
int ingreso(int );
void imprimir(int );

void main() {
      int n[100];
      ingreso(n[100]);
      imprimir(n[100]);
      system("pause");

}

int ingreso(int vect) {
      for (int i = 0; i < 5; i++) {
            cout << "Ingrese un numero: ";
            cin >> vect;
            return vect;
      }
}

void imprimir(int vect) {
      for (int i = 0; i < 5; i++) {
            cout << ingreso(vect) << "\n";
            (vect++);
      }
}

Paso de arreglos utilizando punteros

La manera de declarar la función es:
void func(int *a); 
Podemos acceder a los elementos de un modo alternativo usando un puntero de esta manera:
int *ptr;
 ptr = &mi_arreglo[0]; /* apuntamos nuestro apuntador al primer entero de nuestro arreglo */
ejemplo:
int mi_arreglo[] = {1,23,17,4,-5,100};
int *ptr;
int main(void)
{
 int i;
 ptr = &mi_arreglo[0]; /* apuntamos nuestro puntero
 al primer elemento del arreglo*/
 printf("\n\n");
 for (i = 0; i < 6; i++)
 {
 printf("mi_arreglo[%d] = %d ", i, mi_arreglo[i]); /*<-- A */
 printf("ptr + %d = %d\n",i, *(ptr + i)); /*<-- B */
 }
 return 0;
}

En C, el estándar establece que donde usemos &nombre_de_la_variable[0] podemos reemplazarle con nombre_de_la_variable, esto en el código de ejemplo lo que escribimos como:
ptr = &mi_arreglo[0];
podemos escribirlo como:
 ptr = mi_arreglo;
y obtenemos el mismo resultado.

Arreglos en Memoria Dinámica

Para utilizar un arreglo en memoria dinámica debemos declarar: arreglo = new char[filas]; de esta manera podemos reservar memoria para cada uno de sus espacios.

char * cadena_dinamica = NULL; // arreglo vacio.
 int cantidad = 0;
 //obtenemos un valor de cantidad capturado de consola
 cout<< "Por favor digite el tamaño del arreglo ";
 cin>>cantidad;

 // creamos el arreglo dinámico con el parametro capturado
 cadena_dinamica = new char[cantidad];


Paso de Matrices como Parametros

Para matrices, funciona de la misma forma que existía para arreglos, al momento de declarar la función es importante especificar el numero de columnas  ya que la función receptora debe conoce la estructura interna de la matriz, para poder para acceder a sus elementos, y esto solo es posible informándole de su tipo y dimensiones.

int matriz[100][100];
void main() {

      int n, n1;
     
      cout << "ingrese el tamaño de la fila = ";
      cin >> n;
      cout << "ingrese el tamaño de la columna = ";
      cin >> n1;
      for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; n++) {
                  cout << "ingrese el valor de [" << i+1 << "],[" << j+1 << "]  =";
                  cin >> matriz[i][j];
            }
      }
      for (int i = 0; i < n; i++) {
            for (int j = 0; j < n1; n++) {
                  //gotoxy(i + 5, 2 * j + 3);
                  cout << matriz[i][j];
            }
      }
}
func (int dias[2][12]) {...}

Matrices en memoria dinámica

Para utilizar matrices con memoria dinámica primero debemos reservar el espacio para el numero de filas como si fuera un vector mat = new int*[*dim]; después lo hacemos para cada una de sus columnas, para la lectura de datos utilizamos la estructura siguiente: (&(*(*(mat + i) + j))) o también (*(*(&mat) + i) + j)), y para la escritura (*(*(mat + i) + j))
void diagonal();
void ingreso(int **, int *);
void ingresomat(int **, int *);
void impresion(int **, int *);
int main() {
      diagonal();
      system("pause");
}

void diagonal() {
      int **mat, *dim;
      ingreso(mat, dim);

     
      system("pause");
}

void ingreso(int **mat, int *dim) {
      dim = new (int);
      cout << "ingrese dimension" << endl;
      scanf("%d", (&(*dim)));
      mat = new int*[*dim];
      for (int i = 0; i < *dim; i++) {
            *(mat+i) = new int[*dim];
      }
      ingresomat(mat, dim);
}

void ingresomat(int **mat, int *dim) {
      for (int i = 0; i < *dim; i++) {
            for (int j = 0; j < *dim; j++) {
                  scanf("%d", (&(*(*(mat + i) + j))));

            }
      }

      impresion(mat, dim);
}

void impresion(int **mat, int *dim) {
      for (int i = 0; i < *dim; i++) {
            for (int j = 0; j < *dim; j++) {
                  printf("%d", *(&(*(*(mat + i) + j))));
            }
            cout << endl;
      }
}


Programa que Multiplica 2 matrices en memoria dinamica

void multiplicacion();
void datosmat(int **,int *,int *);
void impresion(int **mat,int *fila, int *columna);
void encerar(int **mat,int *filas, int *columnas);
void multiplicar(int **mat1,int **mat2,int **mat3,int *filas,int *filas2, int *columnas2);

int main(){
      multiplicacion();
      return 0;
}

void multiplicacion(){
      int *filas=new (int),*columnas=new (int);
      cout<<"ingrese las dimensiones de la matriz 1"<<endl;
      cin>>*filas>>*columnas;
      int **mat1=new int*[*filas];
      for(int i=0;i<*filas;i++){
            *(mat1+i)=new int[*columnas];
      }
     
     
      int *filas2=new (int),*columnas2=new (int);
      cout<<"ingrese las dimensiones de la matriz 1"<<endl;
      cin>>*filas2>>*columnas2;
      int **mat2=new int*[*filas2];
      for(int i=0;i<*filas2;i++){
            *(mat2+i)=new int[*columnas2];
      }
     
      cout<<"ingrese datos de matriz 1"<<endl;
      datosmat(mat1,filas,columnas);
     
      cout<<"datos de la matriz 1:"<<endl;
      impresion(mat1,filas,columnas);
     
      cout<<"ingrese datos de la matriz 2"<<endl;
      datosmat(mat2,filas2,columnas2);
     
      cout<<"datos de la matriz 2:"<<endl;
      impresion(mat2,filas2,columnas2);              
     
      int **mat3=new int*[*filas];
      for(int i=0;i<*filas;i++){
            *(mat3+i)=new int[*columnas2];
      }
     
     
      cout<<"datos de la matriz 3"<<endl;
      encerar(mat3,filas,columnas2);
      cout<<endl<<endl;
      cout<<"la multiplicacion es:"<<endl;
      multiplicar(mat1,mat2,mat3,filas,filas2,columnas2);
     
}

void datosmat(int **mat,int *filas, int *columnas){
      for(int i=0;i<*filas;i++){
            for(int j=0;j<*columnas;j++){
                  //scanf("%d",&(*(*(mat+i)+j)));
                  scanf("%d",*(*(&mat)+i)+j);
            //    cin>>mat[i][j];
            }
      }
}

void impresion(int **mat,int *filas, int *columnas){
      for(int i=0;i<*filas;i++){
            for(int j=0;j<*columnas;j++){
                  printf("%d        ",*(*(mat+i)+j));
                  //printf("%d            ",*(*(mat)+i)+j);
            }
            cout<<endl;
      }
}

void encerar(int **mat,int *filas, int *columnas){
      for(int i=0;i<*filas;i++){
            for(int j=0;j<*columnas;j++){
                  *(*(mat+i)+j)=0;
            //    printf("%d",*(*(mat+i)+j));
            }
            cout<<endl;
      }
}

void multiplicar(int **mat1,int **mat2,int **mat3,int *filas,int *filas2, int *columnas2){
      for (int k = 0; k<*filas; k++) {
                        for (int f = 0; f<*columnas2; f++) {
                              for (int c = 0; c<*filas2; c++) {
                                    *(*(mat3+k)+f )= *(*(mat3+k)+f ) + (*(*(mat1+k)+f )       *     (*(*(mat2+k)+f )));
                              }
                              printf("%d  ",*(*(mat3+k)+f));
                        }
                        cout << endl;
                  }
}


Arreglos de punteros

Son vectores cuyos elementos son punteros, cada uno de estos puede apuntar a un tipo de dato especifico

Funciones Recursivas



FUNCIONES RECURSIVAS


Se dice que una función es recursiva cuando se define en función de si misma.
No todas las funciones pueden llamarse a sí mismas, sino que deben estar diseñadas especialmente para que sean recursivas, de otro modo podrían conducir a bucles infinitos, o a que el programa termine inadecuadamente.
Tampoco todos los lenguajes de programación permiten usar recursividad.
C++ permite la recursividad. Cada vez que se llama a una función, se crea un juego de variables locales, de este modo, si la función hace una llamada a sí misma, se guardan sus variables y parámetros, usando la pila, y la nueva instancia de la función trabajará con su propia copia de las variables locales. Cuando esta segunda instancia de la función retorna, recupera las variables y los parámetros de la pila y continúa la ejecución en el punto en que había sido llamada.



Hay algunas limitaciones:
  •     No es posible calcular el factorial de números negativos, no está definido.
  •     El factorial de cero es 1.

Por ejemplo:
Podríamos crear una función recursiva para calcular el factorial de un número entero.
El factorial se simboliza como n!, se lee como "n factorial", y la definición es:

                                                             n! = n * (n-1) * (n-2) * ... * 1

Ventajas y desventajas de la Recursividad:

Ventajas:
·         No es necesario definir la secuencia de pasos exacta para resolver el problema.
·         Soluciones simples, claras.
·         Soluciones elegantes.
·         Soluciones a problemas complejos.

Desventajas:
·         Podría ser menos eficiente.
·         Sobrecarga asociada con las llamadas a sub algoritmos
·         Una simple llamada puede generar un gran número de llamadas Recursivas. (Fact(n) genera n llamadas recursivas)
·         El valor de la recursividad reside en el hecho de que se puede usar para resolver problemas sin fácil solución iterativa.
·         La ineficiencia inherente de algunos algoritmos recursivos.


Un requisito importante para que sea correcto un algoritmo recursivo es que no genere una
secuencia infinita de llamadas así mismo. Claro que cualquier algoritmo que genere tal secuencia
no termina nunca. Una función recursiva f debe definirse en términos que no impliquen a f al
menos en un argumento o grupo de argumentos. Debe existir una "salida" de la secuencia de
llamadas recursivas.
Si en esta salida no puede calcularse ninguna función recursiva. Cualquier caso de definición
recursiva o invocación de un algoritmo recursivo tiene que reducirse a la larga a alguna
manipulación de uno o casos más simples no recursivos.


Ejercicio #1: Factorial de un número

#include <iostream>
using namespace std;
long double factorial(int);
int main()
{   int n;
    cout << "Introduzca numero: ";
    cin >> n;
    cout << "factorial: " << factorial(n) << endl;
    system("pause");
}
long double factorial(int n)
{
    long double fact;
    if (n==0)
        return 1;
    else
         return n*factorial(n-1);





Ejercicio #2: Las Torres De Hanoi


# include <iostream>

using namespace::std;

// FUNCION MOVER_TORRES

void Mover_Torres(int N, int Origen, int Intermedio, int Destino)

{ // Abre funcion Mover_Torres

if (N > 1)

{ // Abre if
Mover_Torres(N - 1, Origen, Destino, Intermedio);

/* Se mueve una torre de N - 1 discos desde la columna origen
pero hacia la columna intermedia ( para dejar la destino libre)
usando la columna destino como intermedia cout << "\nMueve disco "
<< N << " de " << Origen << " a " << Destino <<endl;
con esta instrucción se mueve el disco de la base hacia su destino
Como comento arriba, ahora hay que mover nuevamente la torre de
N - 1 discos hacia el destino original ( en donde se ha puesto el
disco mayor ) Esto implica una segunda llamada recursiva. Ahora
el origen es la columna intermedia a la que se movió la torre y
el destino es el destino primitivo,lo que originalmente era el
origen se usa ahora como columna intermedia */

cout << "\nMueve el disco " << N << " de " << Origen << " a " << Destino << endl;
Mover_Torres(N - 1, Intermedio, Origen, Destino);
} // Cierra if

// El caso limite mas sencillo se resuelve directamente

if (1 == N)
cout << "\nMueve el disco 1 de " << Origen << " a " << Destino << endl;

} // Cierra funcion Mover_Torres

int main()

{ // Abre funcion main
int Discos;
cout << "\nEste programa resuelve el problema clasico de las Torres de Hanoi";
cout << " mediante la recursion." << endl;
cout << "\nPor favor introduzca el numero de discos que quiere mover ";
cout << " de la pila 1 a la pila 3" << endl;
cin >> Discos;

Mover_Torres(Discos, 1, 2, 3);

cout << endl << endl;

return 0;
system("pause");

} // Cierra funcion main




Ejercicio: Multiplicar dos números

#include <iostream>
using namespace std;
int producto(int, int);
int main()
{
 int n1,n2,p;

 cout << "Introduzca primer numero: ";
 cin >> n1;
 cout << "Introduzca segundo numero: ";
 cin >> n2;
 p=producto(n1,n2);
 cout << "producto: " << p << endl;
 system("pause");

}

int producto(int a, int b)
{
 if(a==0 or b==0)
   return 0;
  else
   {
    return a+producto(a,b-1);
   }

}



Gracias

Jossua Orellana G,         Marcelo Olalla. 

Videos Explicativos Referentes al Tema: