¿Qué problemas de programación se resuelven mejor usando punteros? [cerrado]

56

Bueno, básicamente entiendo cómo usar los punteros, pero no la mejor manera de usarlos para hacer una mejor programación.

¿Cuáles son los buenos proyectos o problemas a resolver que involucran el uso de punteros para que pueda entenderlos mejor?

    
pregunta dysoco 11.09.2011 - 23:33

17 respuestas

68

Manipular grandes cantidades de datos en la memoria es donde los punteros realmente brillan.

Pasar un objeto grande por referencia es equivalente a pasar un número antiguo sin formato. Puede manipular las partes necesarias directamente en lugar de copiar un objeto, alterarlo y luego devolver la copia para que se coloque en lugar del original.

    
respondido por el Glenn Nelson 17.09.2011 - 01:43
44

El concepto de puntero le permite referirse a los datos por dirección sin duplicar el almacenamiento de datos. Este enfoque permite escribir algoritmos eficientes como:

  1. Clasificación
    Al mover datos en un algoritmo de clasificación, puede mover el puntero en lugar de los datos en sí mismos; piense en ordenar millones de filas en una cadena de 100 caracteres; guarda muchos movimientos de datos innecesarios.

  2. Listas enlazadas
    Puede almacenar la ubicación del elemento siguiente y / o anterior y no todos los datos asociados con el registro.

  3. Pasando parámetros
    En este caso, usted pasa la dirección de los datos en lugar de los datos en sí. Nuevamente, piense en un algoritmo de compresión de nombres que se ejecuta en millones de filas.

El concepto puede extenderse a estructuras de datos, como bases de datos relacionales, donde un puntero es similar a una clave externa . Algunos idiomas no fomentan el uso de punteros como C # y COBOL.

Se pueden encontrar ejemplos en muchos lugares, tales como:

La siguiente publicación puede ser relevante de alguna manera:

respondido por el NoChance 23.05.2017 - 14:40
29

Me sorprende que ninguna otra respuesta haya mencionado esto: los punteros le permiten crear estructuras de datos no contiguas y no lineales, en donde un elemento puede estar relacionado con muchos otros de formas complejas.

Las listas enlazadas (unidas, dobles y circulares), los árboles (rojo-negro, AVL, trie, binario, partición espacial ...), y los gráficos son ejemplos de estructuras que pueden construirse de forma más natural en términos de referencias, más bien que solo valores.

    
respondido por el Jon Purdy 11.09.2011 - 22:20
8

Una forma simple es en el polimorfismo. El polimorfismo solo funciona con punteros.

Además, utiliza punteros en cualquier momento en que necesite una asignación de memoria dinámica. En C, esto suele ocurrir cuando necesita almacenar datos en una matriz pero no sabe el tamaño en el momento de la compilación. Luego llamaría a malloc para asignar la memoria y un puntero para acceder a ella. Además, ya sea que lo sepa o no, cuando usa una matriz, está usando punteros.

for(int i = 0; i < size; i++)
   std::cout << array[i];

es el equivalente de

for(int i = 0; i < size; i++)
   std::cout << *(array + i);

Este conocimiento te permite hacer cosas realmente geniales como copiar una matriz completa en una línea:

while( (*array1++ = *array2++) != '
for(int i = 0; i < size; i++)
   std::cout << array[i];
')

En c ++, usas new para asignar memoria a un objeto y almacenarlo en un puntero. Lo hace en cualquier momento en que necesite crear un objeto durante el tiempo de ejecución en lugar de hacerlo durante el tiempo de compilación (es decir, un método crea un nuevo objeto y lo almacena en una lista).

Para entender mejor los punteros:

  1. Encuentre algunos proyectos que jueguen con las cadenas y arreglos tradicionales.
  2. Encuentre algunos proyectos que usan herencia.

  3. Aquí está el proyecto en el que me corté los dientes:

Lea en dos n x n matrices de un archivo y realice las operaciones básicas del espacio vectorial en ellas e imprima su resultado en la pantalla.

Para hacer esto, debe usar matrices dinámicas y referirse a sus matrices mediante punteros, ya que tendrá dos matrices de matrices (matrices dinámicas multidimensionales). Una vez que finalice el proyecto, tendrá una idea bastante clara de cómo usar los punteros.

    
respondido por el Jonathan Henson 11.09.2011 - 22:24
8

Para comprender realmente por qué son importantes los punteros, debe comprender la diferencia entre la asignación de almacenamiento dinámico y la asignación de pila.

El siguiente es un ejemplo de una asignación de pila:

struct Foo {
  int bar, baz
};

void foo(void) {
  struct Foo f;
}

Los objetos asignados en la pila solo existen durante la ejecución de la función actual. Cuando la llamada a foo queda fuera del alcance, también lo hace la variable f .

Un caso en el que esto se convierte en un problema es cuando necesitas devolver algo que no sea un tipo integral desde una función (por ejemplo, la estructura Foo del ejemplo anterior).

Por ejemplo, la siguiente función resultaría en el llamado "comportamiento indefinido".

struct Foo {
  int bar, baz
};

struct Foo *foo(void) {
  struct Foo f;
  return &f;
}

Si desea devolver algo como struct Foo * desde una función, lo que realmente necesita es una asignación de pila:

struct Foo {
  int bar, baz
};

struct Foo *foo(void) {
  return malloc(sizeof(struct Foo));
}

La función malloc asigna un objeto en el montón y devuelve un puntero a ese objeto. Tenga en cuenta que el término "objeto" se usa de forma general aquí, que significa "algo" en lugar de objeto en el sentido de programación orientada a objetos.

El programador controla la vida útil de los objetos asignados al montón. La memoria para este objeto se reservará hasta que el programador la libere, es decir, llamando a free() o hasta que el programa salga.

Editar : no pude notar que esta pregunta está etiquetada como una pregunta de C ++. Los operadores de C ++ new y new[] realizan la misma función que malloc . Los operadores delete y delete[] son análogos a free . Mientras que new y delete deben usarse exclusivamente para asignar y liberar objetos de C ++, el uso de malloc y free es perfectamente legal en el código de C ++.

    
respondido por el Mike Steinert 12.09.2011 - 01:25
4

Escriba cualquier proyecto no trivial en C y TENDRÁ que averiguar cómo / cuándo usar los punteros. En C ++, en su mayoría, utilizará objetos habilitados para RAII que administran los punteros internamente, pero en C los punteros tienen una función mucho más prevalente. En cuanto al tipo de proyecto que debe hacer, puede ser cualquier cosa no trivial:

  • Un servidor web pequeño y simple
  • Herramientas de línea de comandos de Unix (less, cat, sort etc.)
  • Algunos proyectos reales que quieres hacer por su propio bien y no solo para aprender

Recomiendo el último.

    
respondido por el Viktor Dahl 11.09.2011 - 21:59
3

Casi todos los problemas de programación que se pueden resolver con punteros se pueden resolver con otros tipos más seguros de referencias (sin referirse a referencias de C ++ , pero el concepto general de CS de tener una variable se refiere a el valor de los datos almacenados en otro lugar).

Punteros por ser una implementación de referencias específica de bajo nivel, donde puede manipular directamente las direcciones de memoria son muy potentes, pero su uso puede ser un poco peligroso (por ejemplo, apuntar a ubicaciones de memoria fuera del programa).

El beneficio de usar punteros directamente es que serán un poco más rápidos al no tener que realizar ninguna comprobación de seguridad. Los lenguajes como Java que no implementan directamente los punteros de estilo C sufrirán un leve impacto en el rendimiento, pero reducirán muchos tipos de situaciones difíciles de depurar.

En cuanto a por qué necesita indirección, la lista es bastante larga, pero esencialmente las dos ideas clave son:

  1. La copia de valores de objetos grandes es lenta y hará que el objeto se almacene en la RAM dos veces (potencialmente muy costoso), pero la copia por referencia es casi instantánea utilizando solo unos pocos bytes de RAM (para la dirección). Por ejemplo, digamos que tiene ~ 1000 objetos grandes (cada uno de los cuales dice alrededor de 1 MB de RAM) en la memoria, y su usuario debe poder seleccionar el objeto actual (en el que actuará el usuario). Tener una variable selected_object que es una referencia a uno de los objetos es mucho más eficiente que copiar el valor del objeto actual en una nueva variable.
  2. Tener estructuras de datos complicadas que se refieren a otros objetos como listas vinculadas o árboles, donde cada elemento en la estructura de datos se refiere a otros elementos en la estructura de datos. La ventaja de referirse a otros elementos en la estructura de datos significa que no tiene que mover todos los elementos de la lista en la memoria simplemente porque insertó un nuevo elemento en el centro de la lista (puede tener inserciones de tiempo constante).
respondido por el dr jimbob 12.09.2011 - 16:31
2

La manipulación de imágenes a nivel de píxel es casi siempre más fácil y más rápida usando punteros. A veces solo es posible usar punteros.

    
respondido por el Dave Nay 11.09.2011 - 22:03
1

Los punteros se utilizan en tantos lenguajes de programación debajo de la superficie sin molestar al usuario. C / C ++ solo te da acceso a ellos.

Cuándo usarlos: tan a menudo como sea posible, porque copiar datos es ineficiente. Cuándo no usarlos: cuando quiera dos copias que puedan ser modificadas individualmente. (Lo que básicamente terminará copiando el contenido de object_1 a otro lugar en la memoria y devolviendo un puntero, esta vez apuntando a object_2)

    
respondido por el mmlac 12.09.2011 - 03:45
1

Los punteros son una parte esencial de cualquier implementación de la estructura de datos en C y las estructuras de datos son una parte esencial de cualquier programa no trivial.

Si desea saber por qué los punteros son tan vitales, sugiero aprender qué es una lista enlazada y tratar de escribir uno sin usar punteros. No te he planteado un desafío imposible, (SUGERENCIA: los punteros se utilizan para hacer referencia a ubicaciones en la memoria, ¿cómo haces referencia a las cosas en los arreglos?).

    
respondido por el dan_waterworth 12.09.2011 - 08:05
0

Como ejemplo de la vida real, crear un libro de pedidos con límite.

el feed ITCH 4.1, por ejemplo, tiene un concepto de órdenes de "reemplazo", donde los precios (y por lo tanto, la prioridad) pueden cambiar. Quieres poder sacar pedidos y trasladarlos a otra parte. Implementar una cola de doble extremo con punteros hace que la operación sea muy fácil.

    
respondido por el Foo Bah 12.09.2011 - 05:31
0

Examinando los diversos sitios de StackExchange, me doy cuenta de que está más en boga hacer una pregunta como esta. En riesgo de críticas y downvotes, seré honesto. Esto no significa troll o flamear, solo quiero ayudar, al dar una evaluación honesta de la pregunta.

Y esa evaluación es la siguiente: Esta es una pregunta muy extraña para un programador de C. Casi todo lo que dice es "No sé C." Si analizo un poco más y de manera más cínica, hay un trasfondo en el seguimiento de esta "pregunta": "¿Existe algún atajo que pueda tomar para adquirir de forma rápida y repentina el conocimiento de un programador en C experimentado, sin dedicar tiempo? para el estudio independiente? " Cualquier "respuesta" que alguien pueda dar no es un sustituto para ir y hacer el trabajo de entender el concepto subyacente y su uso.

Siento que es más constructivo ir a aprender C bien, de primera mano, que ir a la web y preguntar esto a la gente. Cuando sepa que C bien no se molestará en hacer preguntas como esta, será como preguntar "¿Qué problemas se resuelven mejor usando un cepillo de dientes?"

    
respondido por el asveikau 12.09.2011 - 07:33
0

Aunque los punteros realmente brillan cuando se trabaja con objetos de memoria grandes, todavía hay una manera de hacer lo mismo sin ellos.

El puntero es absolutamente esencial para la llamada programación dinámica , es cuando no sabes cuánta memoria necesitarás antes de que se ejecute tu programa. En la programación dinámica, puede solicitar fragmentos de memoria durante el tiempo de ejecución y colocar sus propios datos en ellos, por lo que necesita punteros o referencias (la diferencia no es importante aquí) para poder trabajar con esos fragmentos de datos.

Mientras pueda reclamar cierta memoria durante el tiempo de ejecución y colocar sus datos en la memoria recién adquirida, puede hacer lo siguiente:

  1. Puedes tener estructuras de datos auto-extendibles. Esas son estructuras que se pueden extender reclamando memoria adicional siempre que se agote su capacidad. La propiedad clave de cada estructura autoexpansible es que consta de pequeños bloques de memoria (denominados nodos, elementos de lista, etc., según la estructura) y cada bloque contiene referencias a otros bloques. Estas estructuras "vinculadas" construyen la mayoría de los tipos de datos modernos: gráficos, árboles, listas, etc.

  2. Puede programar usando el paradigma OOP (Programación Orientada a Objetos). Todo el OOP se basa en el uso de variables no directas, sino en referencias a instancias de clase (denominadas objetos) y su manipulación. No puede existir una sola instancia sin punteros (aunque es posible usar clases solo estáticas incluso sin punteros, es una excepción).

respondido por el Alexander Galkin 12.09.2011 - 08:43
0

Es gracioso, acabo de responder una pregunta sobre C ++ y hablé sobre los punteros.

La versión corta es que NUNCA necesita punteros a menos que 1) la biblioteca que está usando lo obligue 2) Necesita una referencia que pueda contener nulos.

Si necesita una matriz, una lista, una cadena, etc., simplemente téngala en la pila y use un objeto stl. Devolver o pasar los objetos STL es rápido (hecho sin marcar) porque tienen un código interno que copia un puntero en lugar de un objeto y solo copiará los datos si se escribe en él. Esto es C ++ normal, ni siquiera el nuevo C ++ 11, lo que facilitará la tarea de los escritores de bibliotecas.

Su pregunta podría responderse en esta parte

Si utiliza un puntero, asegúrese de que esté en una de estas dos condiciones. 1) Está pasando una entrada que puede ser anulable. Un ejemplo es un nombre de archivo opcional. 2) Si quieres regalar la propiedad. Como en el caso de que pase o devuelva el puntero, no le quedarán NINGUNA copia ni usará el puntero que haya regalado

ptr=blah; func(ptr); //never use ptr again for here on out.

Pero no he usado punteros o punteros inteligentes durante mucho tiempo y he perfilado mi aplicación. Se ejecuta muy rápido.

NOTA ADICIONAL: Me doy cuenta de que escribo mis propias estructuras y las paso. Entonces, ¿cómo hago esto sin usar punteros? No es un contenedor STL, por lo que pasar por ref es lento. Siempre carga mi lista de datos / deques / mapas y tal. No recuerdo haber devuelto ningún objeto a menos que fuera algún tipo de lista / mapa. Ni siquiera una cuerda. Miré el código para objetos individuales y me doy cuenta de que hago algo como esto { MyStruct v; func(v, someinput); ... } void func(MyStruct&v, const D&someinput) { fillV; } , por lo que prácticamente devuelvo objetos (múltiples) o preasigno / paso en una referencia para completar (solo).

Ahora, si estaba escribiendo su propio deque, mapa, etc., necesitará usar punteros. Pero no es necesario. Dejemos que STL y posiblemente aumenten la preocupación por eso. Solo necesitas escribir los datos y las soluciones. No contenedores para contenerlos;)

Espero que ahora nunca uses punteros: D. Buena suerte con las libs que te obligan a

    
respondido por el 4 revs, 2 users 97%user2528 12.09.2011 - 09:31
0

Los punteros son muy útiles para trabajar con dispositivos asignados en memoria. Puede definir una estructura que refleje (digamos) un registro de control, luego asignarlo a la dirección del registro de control real en la memoria y manipularlo directamente. También puede apuntar directamente a un búfer de transferencia en una tarjeta o chip si la MMU lo ha asignado al espacio de la memoria del sistema.

    
respondido por el TMN 13.09.2011 - 12:36
0

Veo los punteros como mi dedo índice, solemos hacer un par de cosas:

  1. cuando alguien te pide algo que no puedes llevar, como dónde está la calle, yo "apuntaría" a esta calle, y eso es lo que hacemos en caso de argumentos por referencia
  2. al contar o atravesar algo, usaríamos el mismo dedo, y eso es lo que hacemos en las matrices

Por favor, perdona esta pobre respuesta

    
respondido por el A.Rashad 14.11.2011 - 05:11
0

Como su pregunta está etiquetada como C ++, responderé su pregunta para ese idioma.

En C ++ hay una distinción entre punteros y referencias, por lo tanto, hay dos escenarios donde los punteros (o punteros inteligentes) son necesarios para facilitar ciertos comportamientos. Se pueden usar en otras circunstancias, sin embargo, usted pregunta cuál es la mejor forma de usarlos y, en todas las demás circunstancias, existen mejores alternativas.

1. Polimorfismo

Un puntero de clase base le permite llamar a un método virtual que depende del tipo de objeto al que apunta el puntero.

2. Creando objetos persistentes

Los punteros son necesarios al crear un objeto dinámicamente (en el montón en lugar de la pila). Esto es necesario cuando desea que la vida útil de los objetos sea más larga que el ámbito en el que se crea.

En términos de "buenos proyectos o problemas para resolver", como otros ya han dicho aquí, cualquier proyecto no trivial hará uso de punteros.

    
respondido por el dangerousdave 01.12.2014 - 13:33

Lea otras preguntas en las etiquetas