2009-05-12 21 views
10

¿Cuál es el punto de los punteros en C++ cuando puedo simplemente declarar las variables? ¿Cuándo es apropiado usarlos?¿Cuál es el punto de los punteros?

+2

esto es subjetivo, argumentativo y muy probablemente un duplicado. – lothar

+14

Creo que esta es una pregunta válida de un programador de C++ que comienza. No entiendo por qué ha sido etiquetado como subjetivo, y Babiker hace todo lo posible para no ser discutidor. Solo si alguien fuera a perder karma saltando y diciendo algo como "Y es por eso que C++ es un mal lenguaje en comparación con " se volvería argumentativo, y eso no está sucediendo. –

+4

Acepto, esta es una buena pregunta que probablemente le ocurra a mucha gente que comienza. Si es un duplicado, dale un enlace al hilo original para que el asker pueda encontrar las respuestas. – Chuck

Respuesta

25

Los punteros se entienden mejor por C & C++ 's diferencias en la variable que pasa a las funciones.

Sí, puede pasar una variable completa o solo un puntero (la jerga es por valor o referencia, respectivamente).

Pero, ¿y si la variable es una matriz de bytes de 20 megas, como si decidiera leer un archivo completo en una matriz? Pasarlo por valor sería una tontería: ¿por qué copiarías 20 megas para esta operación, y si terminas modificándolo (es decir, es un parámetro de salida) tienes que copiar los 20 megas de vuelta?

Mejor es simplemente "señalarlo". Usted dice: "aquí hay un indicador de una gran mancha de memoria". Y ese pequeño indirecto ahorra una tonelada de tiempo.

Una vez que comprenda eso, todo lo demás es básicamente lo mismo.La reordenación de los elementos de una lista se convierte simplemente intercambiando punteros en lugar de copiar todos los elementos alrededor, usted no necesita saber qué tan grande son las cosas cuando se empieza, etc

+5

Tu comentario tiene sentido (similar a mi respuesta), pero voy a ser exigente con la terminología. "Aquí hay una referencia a una gran cantidad de memoria", realmente debería ser "Aquí hay un indicador de una gran mancha de memoria". Las referencias tienen significado en C++, y son diferentes de los punteros (aunque, muy similares y relacionadas, son diferentes). – Tom

0

Algunas veces tiene una función que necesita devolver cierta cantidad de memoria que no es una cantidad establecida, como leer desde un archivo.

bool ReadDataFromFile(char** contents); 

Declararía un contenido char * y pasaría la dirección de ese puntero a la función. Esa función asignaría la memoria y su puntero apuntaría a los contenidos a su regreso.

15

Los punteros son más útiles cuando se trata de estructuras de datos cuyo tamaño y forma no se conocen en tiempo de compilación (listas de pensamientos, árboles, gráficos, matrices, cadenas, ...).

Editar

Estas respuestas relacionadas también podrían ayudar (la respuesta superior en el segundo enlace es perfecto para ti):

In C++ I Cannot Grasp Pointers and Classes

What are the barriers to understanding pointers and what can be done to overcome them?

+0

Sí, pero no veo cómo pasar la dirección de memoria puede ayudar a asignar memoria. – Babiker

+1

Necesita alguna forma de referirse a una porción de memoria que ha sido asignada dinámicamente. No se puede crear dinámicamente un nombre de variable, los punteros permiten referencia indirecta a la memoria ("ese compañero sentado al final de la barra" frente a "Sam"). –

2

punteros son también grandes para pasar un argumento mutable a una función para que la persona que llama pueda "ver el cambio". Puede preguntarse, "¿pero por qué no usar una referencia?". Me gusta el argumento de Google:

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments

+0

Solía ​​ser un fanático de esa idea, pero la he lanzado recientemente. Creo que lo recogí de "Code Complete". Habiendo usado ambos, no creo que haga ninguna diferencia, porque la persona que llama puede ver que un cambio es posible por el hecho de que el parámetro es una referencia no const. Puede marcar la diferencia si tiende a tener funciones grandes, por lo tanto, cuando ve * o -> sabe que algo está fuera de la función está cambiando. Creo que es una de esas cosas que debería ser estándar en todo un proyecto, pero qué convención se utiliza no es tan importante IMO. – markh44

1

que tenían exactamente la misma pregunta cuando estaba aprendiendo punteros, que simplemente no parece importante, pero a medida que avanza, se enteran de que son a veces muy útil.

Los apuntadores se utilizan a menudo en situaciones de programación. Por ejemplo, cuando hace referencia a una matriz por nombre, como array[i] = 3; El compilador está haciendo un poco de matemática de lujo que acaba convirtiendo ese código en

(dirección de la matriz) + (sizeof (elementos de la matriz) * i) = 3;

También hacen posibles árboles, listas de enlaces y otras estructuras de datos, que descubrirá a medida que aprenda más.

+0

Nifty. array [i] == i [array] –

-3

De Wikipedia:

referencias C++ difieren de punteros en varias maneras esenciales:

  • no es posible hacer referencia directamente a un objeto de referencia después de se define; cualquier aparición de su nombre se refiere directamente al objeto que referencias.
  • Una vez que se crea una referencia, no se puede hacer más tarde para hacer referencia a otro objeto; decimos que no puede ser reseated. Esto a menudo se hace con punteros .
  • Las referencias no pueden ser nulas, mientras que los punteros pueden; cada referencia hace referencia a a algún objeto, aunque puede o puede ser no válido.
  • Las referencias no se pueden inicializar. Debido a que es imposible reiniciar una referencia, deben ser inicializados tan pronto como se creen . En particular, local y variables globales deben ser inicializado donde están definidos, y las referencias que son miembros de datos de clase casos se debe inicializar en la lista inicializador de constructor de la clase.

Con las limitaciones anteriores, los punteros son todo lo que tienes como un contenedor ligero para hacer referencia a objetos, especialmente si usted está haciendo algo con polimórfica o dinámico. La matriz dinámica de punteros de clase abstractos puros para representar ventanas puede ser un ejemplo.

Puesto que soy demasiado perezoso para pensar en un ejemplo de polimorfismo Voy a tirar de uno de cplusplus.com:

// pointers to base class 
#include <iostream> 
using namespace std; 

class CPolygon { 
    protected: 
    int width, height; 
    public: 
    void set_values (int a, int b) 
     { width=a; height=b; } 
    }; 

class CRectangle: public CPolygon { 
    public: 
    int area() 
     { return (width * height); } 
    }; 

class CTriangle: public CPolygon { 
    public: 
    int area() 
     { return (width * height/2); } 
    }; 

int main() { 
    CRectangle rect; 
    CTriangle trgl; 
    CPolygon * ppoly1 = &rect; 
    CPolygon * ppoly2 = &trgl; 
    ppoly1->set_values (4,5); 
    ppoly2->set_values (4,5); 
    cout << rect.area() << endl; 
    cout << trgl.area() << endl; 
    return 0; 
} 

En el código anterior, puntero CPolygon * se utiliza para hacer referencia a CRectangle objeto y CTriangle objeto.

+2

Los apuntadores no son necesarios o incluso preferidos en ese ejemplo - las referencias son. –

1

En el nivel más básico, los punteros le permiten asociar bloques de memoria disjuntos. Un ejemplo simple (ideado, por cierto) de que los punteros podrían ayudarlo estaría en un algoritmo que requiere una matriz de 1000000000000 enteros. una matriz de este tipo sería demasiado grande para caber dentro de la RAM de la máquina en la que estoy escribiendo en este momento si lo intentara una definición como:

int bigMatrix[1000000000000]; // I can't allocate this much contiguous memory 

Sin embargo, si se crea una única matriz de punteros, que pueda Mantenga las sub-matrices en una matriz de discos de tamaño medio.

int *bigMatrix[1000000]; // Each pointer refers to a sub-array 
         // of 1000000 elements on disk 

Es cierto, voy a tener que escribir código a la página en esas subredes si/cuando el usuario lo requiere, incluyendo ocultar la notación de matriz detrás de un método de acceso. Dicho esto, los punteros me permiten crear las asociaciones ad-hoc que necesito cuando las necesito.

0

Además de la eficiencia y la flexibilidad.El punto principal de los punteros en C/C++ es que así es como funciona el hardware, no se puede obtener un controlador de dispositivo, administrador de memoria o caché eficiente sin utilizar punteros en algún punto de la línea.

Uno de los principales objetivos de diseño para el primer compilador C era ser un "lenguaje ensamblador portátil" y poder hacer en un lenguaje de alto nivel todo lo que pudieras hacer con el código ensamblador/máquina tradicional. Esto significa poder manipular direcciones directamente, que es el punto de los punteros.

Sin embargo, siguiendo el principio KISS no use punteros a menos que realmente estén haciendo las cosas más simples.

0

Desde una perspectiva arquitectónica, los punteros son una forma económica para modelar un 0 .. n relación:

struct A { 
    vector<const B *> *pBees; 
    A() : pBees(nullptr) {} 
    void notice_bee(const B *pB) { 
    if (!pBees) 
     pBees = new vector<const B *>; 
    pBees.push_back(pB) 
    } 
    ~A() { 
    delete pBees; // no need to test, delete nullptr is safe 
    } 
    size_t bees_noticed() { return pBees ? pBees->size : 0 } 
}; 

Si la gran mayoría de los objetos A nunca tendrá que prestar atención a cualquier objeto B, hay no hay razón por la cual cada objeto A debe tener un vector de longitud cero. En Gnu C++ 4.0.1, sizeof (vector) es 12; sizeof (vector *) es 4.

0

Supongamos que escribe un editor de texto. En este caso, no conoce el tamaño del documento por adelantado. Usted puede verse tentado a declarar algo así como

 
    char Document[10000]; 

pero entonces, ciertamente, algún día alguien tendrá que utilizar su editor en un documento mucho más grande. Entonces este intento es inútil; y lo que necesita es una forma de solicitar memoria nueva en runtime (en lugar de tiempo de compilación).

La forma en C++ de hacer esto es usar el operador nuevo, que devuelve un puntero a la memoria recién asignada:.

 
    char* pDocument = new char[getSizeOfDocument()]; 

(Tenga en cuenta que este ejemplo se simplifica En la vida real, que sin duda no lo hacen es como esto, pero en su lugar use algo como std :: string y std :: vector, que internamente hacen esta asignación para usted)

0

Me parece que aún no ha aprendido sobre la asignación dinámica de memoria. Hay dos formas de asignar memoria en C++: estática y dinámicamente. Ya está familiarizado con la asignación estática (es decir, declarando variables). Esto es genial si en el momento de escribir su programa sabe exactamente cuántas variables (o más bien, memoria) necesita.

Pero, ¿y si no? Por ejemplo, digamos que estás leyendo y contiene un montón de números de los que debes hacer un seguimiento. ¿Por qué? No lo sé, pero ese no es el punto.

Bien se podría comenzar con una matriz:

int array[100]; 

Pero lo que si hay más de 100 números en el archivo? Con el tiempo usted desea una solución más flexible:

int *array = new int[size]; 
// do stuff 
delete [] array; 

Esto le da mucha más flexibilidad y le permite crear estructuras de datos más dinámicos.

0

Los punteros almacenan una dirección de memoria, por lo que los usaría cada vez que necesitara la dirección de memoria de algo. Esto puede ser útil para cosas como la administración de memoria, saber dónde están almacenados sus datos. Mi profesor nos dijo que esto es algo hermoso para los programas avanzados en términos de garantizar que sus datos estén ubicados contiguamente en la memoria (como las cadenas de estilo c).

Espero que esto sea una forma de ayuda para usted!

-Zen, un novato en C++