Autor Tema: Apuntadores en C  (Leído 977 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Conectado Rock Lee

  • Administrador
  • *
  • Mensajes: 1122
    Ingreso: Enero de 2014
  • Sexo: Masculino
  • ar
  • Digitalizando tu Mundo
    • Ver Perfil
    • La nueva era del conocimiento
Apuntadores en C
« on: 07 Agosto de 2014, 12:22 pm »
Bueno acá ando con un poco mas navegando por la red encontré algo interesante, o eso creo, sobre apuntadores en C que al leerlo me pareció sencillo de entender y comprender por eso vamos a compartirlo en este momento, con unas pequeñas mejoras.... lo primero:

Definición: Los apuntadores son las capacidades mas difíciles de manejar en C. Los apuntadores permiten a los programas simular llamadas por referencia, crear y manipular estructuras de datos, es decir, estructuras de datos que pueden crecer o encogerse, como son listas enlazadas, colas de espera, pilas y árboles.

Bien ahora tenemos en la mente que son los apuntadores en C por definición daremos paso a las Declaraciones e inicialización de variables de apuntadores

Los apuntadores son variables que contienen direcciones de memoria como sus valores, por lo regular una variable contiene directamente un valor especifico. Un apuntador, por otra parte, contiene la dirección de una variable que contiene un valor especifico. En este sentido, un nombre de variable se refiere directamente a un valor y un apuntador se refiere indirectamente a un valor.
El referirse a un valor a través de un apuntador se conoce como indireccion, los apuntadores como cualquier otra variable, deben ser declarados antes de que puedan ser utilizados.

Código: (C) [Seleccionar]
int *contador,cont;
Declaramos la variable contador siendo del tipo int* [en otras palabras, un apuntador a un valor entero] y se lee "contador es un apuntador a int" o bien "contador apunta a un objeto del tipo entero". También, la variable cont se declara como un entero, no un apuntador a un entero. El * solo se aplica a contador en la declaración. Cuando el * se utiliza de esta forma en una declaración, indica que la variable que se esta declarando es un apuntador.
Los apuntadores pueden ser declarados para apuntar a objetos de cualquier tipo de datos, la misma puede ser inicializado a 0, NULL o a una dirección. [Nota] Un apuntador con el valor NULL apunta a nada [Nota]


Ahora pasamos a los Operadores de apuntador

El & u operador de dirección ,es un operador unitario que regresa la dirección de su operando. Por ejemplo, supongamos las declaraciones:

Código: (C) [Seleccionar]
int y=10;
int *yNav;

yNav = &y

En este pequeño código vemos como asignamos la dirección de la variable y a la variable de apuntador yNav La yNav se dice entonces que "apunta a" y.

El operador *, conocido comúnmente como el operador de indirección o de desreferencia, regresa el valor del objeto hacia el cual su operando apunta, es decir, un apuntador.

Por ejemplo siguiendo con nuestro enunciado

Código: (C) [Seleccionar]
printf("%d", *yNav);
Usando printf (Parametros) vamos que imprime el valor de la variable y [10]. Ademas utilizar * de esta forma se conoce como desreferenciar a un apuntador. Los operadores & y * son complementarios el uno del otro cuando se aplican ambos de manera consecutiva a yNav, en cualquier orden, el mismo resultado sera impreso.

Para comprender un poco mejor lo que venimos hablando dejare un ejemplo rápido aplicándolo:

Código: (C) [Seleccionar]
#include <stdio.h>

int main()
{
    int a;          //a es un entero
    int *aNav;      //aNav es un apuntador a un entero
   
    a=10;
    aNav = &a;      //aNav apunta a la dirección de a
   
    printf("La dirección de a es %p\n"
           "El valor de aNav es %p\n\n",&a,aNav);    //Recordar que %p en el printf nos extrae la localización de memoria en valor hexadecimal
   
    printf("El valor de a es %d\n"
           "El valor de *aNav es %d\n\n",a,*aNav);
           
    printf("Probando que * y & son complementarios uno del otro\n&*aNav = %p\n"
           "*&aNav = %p\n",&*aNav,*&aNav);
    return 0;
}

[Nota]La dirección de a y el valor de aNav son idénticos en la salida,confirmando asi que de hecho la dirección de a ha sido asignada a la variable de apuntador aNav [Nota]


Bien ahora pasando a otra parte de la explicación sin dudas surge el tema Cómo llamar funciones por referencia

Existen dos formas de pasar argumentos a una función llamada por valor o por referencia, en C todas las llamadas de función son llamadas por valor. Como se sabe se puede utilizar return para regresar un valor de una función llamada hacia el llamador [o para regresar el control de una función llamada sin regresar un valor]. Muchas funciones requieren la capacidad de modificar una o mas variables del llamador, o de pasar un apuntador a un objeto de datos grande, para evitar la sobrecarga de pasar el objeto en llamada por valor [lo que, naturalmente, requiere el hacer una copia del objeto]. Para estos fines ,C proporciona las capacidades de simulación de llamadas por referencia.
En C, los programadores utilizan apuntadores y el operador de indirección para simular llamadas por referencia. Cuando se llama a una función con argumentos que deban ser modificados, se pasan las direcciones a los argumentos.
Algo importante que debemos de recordar los arreglos no son pasados mediante el operador & porque C pasa de forma automatica la posición inicial en memoria del arreglo [el nombre de un arreglo es equivalente a &arregloNuevo[0]]. Para comprender esto un poco mejor dejare 2 ejemplos sencillos...:

Código: (C) [Seleccionar]
/* Ejemplo 1 */
#include <stdio.h>

int NavajaValor(int);
int main()
{
    int numero = 10;
    printf("El valor inicial de numero es %d\n",numero);
    numero = NavajaValor(numero);
    printf("El nuevo valor de numero es %d\n",numero);
    return 0;
}
int NavajaValor(int n)
{
    return n*n*n;
}

/* Ejemplo 2 */
#include <stdio.h>

void NavajaReferencia(int *);
int main()
{
    int numero = 20;
    printf("El valor inicial de numero es %d\n",numero);
    NavajaReferencia(&numero);
    printf("El nuevo valor de numero es %d\n",numero);
    return 0;
}
void NavajaReferencia(int *nNav)
{
    *nNav = (*nNav)*(*nNav)*(*nNav);
}

Análisis: En el Ejemplo 1 el programa pasa la variable numero a la función NavajaValor, utilizando llamada por valor. La funcion NavajaValor eleva al cubo su argumento y pasa su nuevo valor de regreso a main utilizando el enunciado return, el nuevo valor se asigna a numero en main.

 En el Ejemplo 2 el programa pasa la variable numero utilizando llamada por referencia, se pasa la dirección de numero a la función NavajaReferencia, la función toma un apuntador a int conocido como nNav como argumento. La función desreferencia el apuntador y eleva al cubo el valor hacia el cual apunta nNav.Esto cambia el valor de numero dentro de main. Una función que recibe una dirección como argumento debe definir un parámetro de un apuntador para recibir la dirección. Por ejemplo, el encabezado para la funcion NavajaReferencia es void NavajaReferencia(int *nNav);

El encabezado especifica que NavajaReferencia recibe la dirección de una variable entera como argumento, almacena la dirección local en nNav, y no regresa ningún valor. El prototipo de función para NavajaReferencia contiene un int * entre paréntesis, como en el caso de otros tipos de variables [en los prototipos de función no es necesario incluir los nombres de los apuntadores]

En el encabezado de función y en el prototipo para una función que espera un arreglo de un subindice como argumento, puede ser utilizada la notación de apuntador en la lista de parámetros de NavajaReferencia. El compilador no diferencia entre una función que recibe un apuntador una función que recibe un arreglo de un solo subindice. Esto significa que la función debe "saber" cuando está recibiendo un arreglo o una variable para la cual deberá llevar a cabo una llamada por referencia. Cuando el compilador encuentre un parámetro de función correspondiente a un arreglo de un subindice de la forma int b [], el compilador convertirá el parámetro a la notación de apuntador int *b, ambas formas son intercambiables.


Bueno hasta aquí llegamos con este pequeño repaso de C pero no olviden que la Teoría sin Practica no mucho se aprende por el cual dejare planteado un pequeño problema para ver a que conclusiones llegan :)


Problema:

Teniendo en cuenta lo que ah visto recientemente realice las siguientes actividades:
  • Escriba el encabezado de función de una función llamada intercambio que tome como parámetros dos apuntadores a números de punto flotante "z" y "x", donde "x" no regresa valor.
  • Escriba el prototipo de función para la función de la parte I
  • Escriba el encabezado de función para la función Prueba, que regresa un entero y que toma como parámetros el entero x y un apuntador a la función "Falla". La función "Falla" toma un parámetro entero y regresa un entero.

Finalmente con esto concluimos este pequeño tema, ademas queda aclarar me gustaría que dejaran sus pruebas de código para "compararlos" y formas de mejorar los mismos..


...Saludo Familia!...
« Última Modificación: 07 Agosto de 2014, 12:31 pm por Rock Lee »