¿Las mentes jóvenes necesitan aprender los conceptos de puntero?

89

¿Por qué el maestro C Dennis Ritchie introdujo los punteros en C? ¿Y por qué los otros lenguajes de programación como VB.NET o Java o C # los eliminaron? He encontrado algunos puntos en Google y también quiero escuchar sus comentarios. ¿Por qué están eliminando los conceptos de puntero en los idiomas modernos?

La gente dice que C es el lenguaje básico y los punteros es el concepto que hace que C sea poderoso y sobresaliente y que C todavía compita con lenguajes más modernos. Entonces, ¿por qué eliminaron los punteros en lenguajes más modernos?

¿Crees que el conocimiento de los punteros sigue siendo importante para los nuevos programadores? La gente está usando VB.NET o Java en estos días, que admite funciones más avanzadas que C (y no usa ningún concepto de puntero) y muchas personas como yo veo ahora (mis amigos) eligen estos idiomas ignorando C porque admiten funciones avanzadas. Les digo que comiencen con C. Dicen que es un desperdicio aprender los conceptos de punteros cuando estás haciendo cosas avanzadas en VB.NET o Java que no son posibles en C.

¿Qué piensas?

Actualizado :

Los comentarios que leí en Google son:

  1. Las computadoras anteriores eran demasiado lentas y no estaban optimizadas.

  2. El uso de punteros permite acceder directamente a una dirección y esto ahorra tiempo en lugar de hacer una copia de ella en llamadas a funciones.

  3. La seguridad es significativamente peor con los punteros, y es por eso que Java y C # no los incluyeron.

Estos y algunos más lo que encontré. Todavía necesito algunas respuestas valiosas. Eso sería muy apreciado.

    
pregunta niko 05.09.2011 - 22:50

16 respuestas

127

En aquellos días, los desarrolladores trabajaban mucho más cerca del metal. C fue esencialmente un reemplazo de alto nivel para el ensamblaje, que es casi lo más cercano al hardware que puede obtener, por lo que era natural que necesitara punteros para ser eficiente en la resolución de problemas de codificación. Sin embargo, los punteros son herramientas afiladas, que pueden causar un gran daño si se usan sin cuidado. Además, el uso directo de los punteros abre la posibilidad de muchos problemas de seguridad, que no eran un problema en ese entonces (en 1970, Internet consistía en unas pocas docenas de máquinas en un par de universidades, y ni siquiera se llamaba así). ...), pero se hizo cada vez más importante desde entonces. Por eso, en la actualidad, los lenguajes de nivel superior están diseñados conscientemente para evitar los punteros de memoria en bruto.

Decir que "las cosas avanzadas hechas en VB.Net o Java no son posibles en C" muestra un punto de vista muy limitado, por decir lo menos :-)

En primer lugar, todos estos lenguajes (incluso el ensamblaje) están completados por Turing, por lo que en teoría, todo lo que sea posible en un solo idioma es posible en todos. Solo piense en lo que sucede cuando se compila y ejecuta una pieza de código VB.Net o Java: finalmente, se traduce (o se asigna a) el código de la máquina, porque eso es lo único que la máquina entiende. En lenguajes compilados como C y C ++, puede obtener el cuerpo completo de código de máquina equivalente al código fuente original de nivel superior, como uno o más archivos / bibliotecas ejecutables. En los lenguajes basados en máquinas virtuales, es más complicado (y puede que ni siquiera sea posible) obtener la representación de código de máquina equivalente completa de su programa, pero aún así, eventualmente, está en algún lugar, dentro de los profundos recesos del sistema de tiempo de ejecución y el JIT.

Ahora, por supuesto, es una pregunta completamente diferente si alguna solución es factible en un lenguaje específico. Ningún desarrollador sensato comenzaría a escribir una aplicación web en ensamblaje :-) Pero es útil tener en cuenta que la mayoría o todos esos lenguajes de nivel superior están construidos sobre una gran cantidad de código de biblioteca de clase y tiempo de ejecución, una gran parte de que se implementa en un lenguaje de nivel inferior, normalmente en C.

Así que para llegar a la pregunta,

  

¿Cree que el conocimiento sobre los indicadores a los jóvenes es importante?

El concepto detrás de los punteros es indirection . Este es un concepto muy importante y, en mi humilde opinión, todo buen programador debería comprenderlo en un cierto nivel. Incluso si alguien está trabajando únicamente con idiomas de nivel superior, la indirección y las referencias siguen siendo importantes. No entender esto significa no poder usar toda una clase de herramientas muy potentes, lo que limita seriamente la capacidad de resolución de problemas de uno a largo plazo.

Así que mi respuesta es sí, si quieres convertirte en un programador realmente bueno, también debes entender los punteros (así como la recursión: este es el otro obstáculo típico para los desarrolladores en ciernes). Es posible que no necesite comenzar con él. No creo que C sea la mejor lengua como primera lengua en la actualidad. Pero en algún punto uno debería familiarizarse con el direccionamiento indirecto. Sin él, nunca podremos entender cómo funcionan realmente las herramientas, las bibliotecas y los marcos que estamos utilizando. Y un artesano que no entiende cómo funcionan sus herramientas es muy limitado. Justo lo suficiente, uno puede entenderlo en lenguajes de programación de nivel superior también. Una buena prueba de fuego es implementar correctamente una lista doblemente enlazada: si puedes hacerlo en tu idioma favorito, puedes decir que entiendes lo suficientemente bien la indirección.

Pero si no es por otra cosa, deberíamos hacerlo para aprender a respetar a los programadores de la antigüedad que lograron construir cosas increíbles utilizando las herramientas ridículamente simples que tenían (en comparación con las que tenemos ahora). Todos estamos parados sobre los hombros de gigantes, y nos hace bien reconocer esto, en lugar de fingir que somos los mismos gigantes.

    
respondido por el Péter Török 05.09.2011 - 12:29
38

Creo que necesitas diferir.

Java y otros lenguajes de nivel superior no eliminaron los punteros. Lo que hicieron fue eliminar aritmética de puntero llano.

De hecho, Java todavía permite una aritmética de punteros protegido y restringida : el acceso a la matriz. En la antigua C simple, el acceso a la matriz no es más que una desreferenciación. Es una notación diferente, un azúcar sintáctico, si quiere, para comunicarse claramente, lo que está haciendo.
Aún así, array[index] es equivalente a *(array+index) . Debido a eso, también es equivalente a index[array] , aunque supongo que algunos compiladores de C podrían darte una advertencia, si lo haces.
Como corolario, pointer[0] es equivalente a *pointer . Eso es simplemente porque el "puntero a una matriz" es la dirección de la primera entrada de la matriz y las direcciones de los elementos posteriores se calculan agregando el índice.

En Java, la aritmética de puntero simple (referencia y desreferenciación) ya no existe. Sin embargo existen punteros. Los llaman referencias, pero eso no cambia lo que es. Y el acceso a la matriz sigue siendo exactamente lo mismo: mire la dirección, agregue el índice y use esa ubicación de memoria. Sin embargo, en Java, verificará si ese índice está o no dentro de los límites de la matriz que originalmente asignó. Si no, lanzará una excepción.

Ahora, la ventaja del enfoque de Java es que no tiene código, que simplemente escribe ciegamente bytes arbitrarios en ubicaciones de memoria arbitrarias. Esto mejora la seguridad y también la seguridad, porque si no compruebas los desbordamientos del búfer y el tiempo de ejecución lo hará por ti.

La desventaja de esto es que es simplemente menos potente. Es posible realizar una programación de memoria segura en C. Es imposible beneficiarse de la velocidad y las posibilidades de la programación insegura en Java.

En realidad, no hay nada difícil acerca de los punteros o la aritmética de punteros. Normalmente solo se explican de manera complicada, mientras que todo lo que un puntero es, es un índice de una matriz gigante (su espacio de memoria), todo lo que hace referencia a un valor le da el índice donde encontrarlo, todo lo que hace la desreferenciación es buscar el valor en un índice dado. (Esto es solo un poco simplificado, porque no tiene en cuenta que los valores son de diferente tamaño en la memoria, dependiendo de su tipo. Pero ese es un detalle circunstancial, en lugar de una parte del concepto real)

En mi humilde opinión, todos en nuestro trabajo deberían poder entenderlo, o simplemente están en el campo equivocado.

    
respondido por el back2dos 05.09.2011 - 13:08
24

El concepto de punteros es importante en el cuerpo general de conocimientos de programación de computadoras. Comprender el concepto es bueno para los futuros programadores o programadores de cualquier idioma, incluso si el lenguaje no lo admite directamente.

Los punteros tienen su uso en Estructuras de datos (listas vinculadas) y Diseño de base de datos (Clave externa).

Los lenguajes como VB y C # pueden pasar datos por "referencia" a métodos, que se pueden considerar como un tipo de puntero.

La comprensión de dónde se asignan los datos en la memoria (pila frente a montón) sigue siendo importante para la eficiencia de los algoritmos.

En mi opinión, aprender lo básico es correcto.

    
respondido por el NoChance 05.09.2011 - 11:42
19

¡Sí, sí, sí, sí y sí!

Si no sabes lo básico NUNCA podrás resolver los problemas realmente difíciles, extraños, difíciles y complicados que se te presenten.

Y si entiendes los conceptos básicos realmente bien, eres MUCHO más comercial en el mercado laboral.

Una vez trabajé con un chico que había estado programando durante 10 años, y no tenía idea de cómo funcionaban los punteros. Yo (mucho más joven) pasé horas en una pizarra educándolo. Eso me abrió los ojos. No tenía ninguna IDEA sobre tantas cosas básicas.

Sepa todo lo que pueda.

    
respondido por el quickly_now 05.09.2011 - 12:54
17

Sí, la comprensión es importante.

Hace unos meses estaba programando en C # y quería hacer una copia de una lista. Por supuesto, lo que hice fue NewList = OldList; y luego comencé a modificar NewList . Cuando intenté imprimir ambas listas, ambas eran iguales, ya que NewList era solo un puntero a OldList y no una copia, así que en realidad estaba cambiando OldList todo el tiempo. No me tomó mucho tiempo darme cuenta de eso, pero algunos de mis compañeros no fueron tan rápidos y tuvieron que explicarme por qué sucede esto.

Ejemplo:

List<int> a = new List<int>();
a.Add(2);
a.Add(9);
a.Add(8);
a.Add(1);
List<int> b = new List<int>();
b = a; //Does not make a copy, b is just a synonym!
b.Sort();
for (int i = 0; i < a.Count; i++)
{
    Console.WriteLine("a: " + a[i] + " b: " + b[i]);
}

Y, por supuesto, el resultado es así:

a: 1 b: 1
a: 2 b: 2
a: 8 b: 8
a: 9 b: 9

Saber cómo usarlos no es tan importante, ¡pero entenderlos es crucial!

    
respondido por el Bojan Kogoj 05.09.2011 - 23:06
14

¡Apunta el concepto! = ¡Apunta la aritmética! = Apunta la sintaxis

Lo primero importa siempre, si necesita (y lo hace) la comprensión de la copia profunda / superficial, pase por referencia / pase por valor, etc. Los otros dos importan solo si su idioma du jour le permite usarlos.

    
respondido por el Alien Life Form 05.09.2011 - 15:25
14
  

¿Por qué el maestro C Dennis Ritchie introdujo los punteros en C?

Porque los punteros son un mecanismo muy poderoso que se puede usar de muchas maneras.

  

¿Y por qué los otros lenguajes de programación como VB.NET o Java o C # los eliminaron?

Porque los punteros son un mecanismo muy peligroso que puede ser mal utilizado de muchas maneras.

Creo que los programadores deberían aprender sobre los punteros, pero desde una perspectiva educativa, no es aconsejable presentarlos temprano. La razón es que se usan para muchos propósitos diferentes, es difícil decir como principiante por qué estás usando un puntero en una circunstancia particular.

Aquí hay una lista incompleta para qué punteros se usan:

  • asignación dinámica ( new T )
  • estructuras de datos recursivas ( struct T { T* next; /* ... */ }; )
  • iteradores sobre matrices ( for (T* p = &a[0]; p != &a[0] + n; ++p) { ... } )
  • acceso compartido a objetos ( T* new_pointer = existing_pointer; )
  • polimorfismo de subtipo ( T* pointer_to_base = pointer_to_derived; )
  • llamada heredada por referencia ( mutate(&object); )
  • tipos opcionales ( if (p) { /* ... */ } )

Tenga en cuenta que el uso de un solo mecanismo para todos estos conceptos demuestra tanto el poder como la elegancia para el programador experimentado y el gran potencial de confusión para alguien nuevo en la programación.

    
respondido por el FredOverflow 05.09.2011 - 23:06
12

¿Por qué? Puedes escribir un gran sistema con el diseñador de formularios y el generador de código. ¿No es suficiente? (ironía)

Y ahora, en serio, los indicadores no son una parte crucial de la programación en muchas áreas, pero permiten que las personas entiendan cómo funcionan los elementos internos. Y si no tenemos a nadie que entienda cómo funcionan los elementos internos, habrá una situación en la que SQL2020, Windows 15 y Linux 20.04 se escribirán en una máquina virtual recolectada con más de 30 capas de abstracción, con código generado mediante IDE, en JavaScript. .

Esto definitivamente no es lo que quiero ver.

Así que sí, ¡tienen que hacerlo, definitivamente!

    
respondido por el Coder 05.09.2011 - 12:12
7

Ni Java ni C # eliminaron los punteros, tienen referencias que son casi iguales. Lo que se eliminó es la aritmética de punteros, que se puede omitir en un curso de introducción.
No se podría hacer una aplicación no trivial sin el concepto de punteros o referencias, por lo que vale la pena enseñar (no se podría hacer una asignación de memoria dinámica sin ellos).

Considere lo siguiente en C ++ y Java, y creo que no es muy diferente en C #:
aClass *x = new aClass();
aClass x = new aClass();
Realmente no hay demasiada diferencia entre los punteros y las referencias, ¿verdad?
La aritmética de punteros debe evitarse a menos que sea necesario y al programar con modelos de alto nivel, por lo que no hay mucho problema allí.

    
respondido por el Petruza 05.09.2011 - 15:41
6

El programador profesional debe dominar los punteros.

Las personas que desean saber sobre programación deben conocer su existencia y sus implicaciones, pero no necesariamente utilizarlas.

Las personas que quieren resolver problemas personales a través de la programación (como yo, que usan muchos scripts de Python) podrían ignorarlos en absoluto.

Bueno, esa es mi opinión ...; o)

    
respondido por el heltonbiker 05.09.2011 - 15:03
3

Los punteros de dirección variable son un caso específico del concepto más generalizado de direccionamiento indirecto. La indirección se utiliza en la mayoría (¿todos?) De los idiomas modernos en muchos constructos, como delegados y devoluciones de llamada. Comprender el concepto de indirección le permite saber cuándo y cómo usar mejor estas herramientas.

    
respondido por el Dave Nay 05.09.2011 - 15:17
3

Absufreakinglutely YES ! Todas las personas que programan deben comprender los punteros y el direccionamiento indirecto.

Los punteros son cómo se realiza una gran cantidad de acceso a datos en todos los idiomas. Los punteros son una característica del hardware de todos los microprocesadores. Lenguajes de alto nivel como Java, VB y amp; C # esencialmente bloquea el acceso directo a los punteros de los usuarios del idioma con referencias. Las referencias se refieren a objetos a través del esquema de administración de memoria del idioma (podría ser un puntero con metadatos o solo un número para la tabla de memoria, por ejemplo).

Comprender cómo funcionan los punteros es fundamental para entender cómo funcionan realmente las computadoras. Los punteros también son más flexibles y potentes que las referencias.

Por ejemplo, la razón por la que las matrices comienzan en el índice cero es porque las matrices son en realidad taquigrafía para la aritmética de punteros. Sin saber cómo funcionan los punteros, muchos programadores principiantes no obtienen matrices.

int a, foo[10];
foo[2] = a;

La línea 2 en aritmética de punteros sería:

*(foo + sizeof(int) * 2) = a;

¡Sin comprender los punteros, no se puede entender la administración de la memoria, la pila, el montón o incluso las matrices! Además, es necesario comprender los punteros y la desreferenciación para comprender cómo se pasan las funciones y los objetos.

TL: DR : comprender los punteros es fundamental para comprender que las computadoras realmente funcionan .

    
respondido por el CyberSkull 06.09.2011 - 10:02
2

Creo que se reduce al hecho de que la necesidad de lidiar con los punteros desapareció, ya que los programadores trataron menos con el hardware directo en el que se estaban ejecutando. Por ejemplo, asignar una estructura de datos de listas vinculadas de forma que se ajuste perfectamente a la secuencia de módulos de memoria de 640 bytes que tenía el hardware especializado.

Tratar los punteros manualmente puede ser propenso a errores (lo que lleva a fugas de memoria y código explotable) y requiere mucho tiempo para hacerlo bien. Por lo tanto, Java y C #, etc., ahora administran su memoria y sus punteros a través de sus Máquinas Virtuales (VM). Esto es posiblemente menos eficiente que usar C / C ++ en bruto, aunque las máquinas virtuales están mejorando constantemente.

C (y C ++) todavía son lenguajes ampliamente utilizados, especialmente en los espacios de computación de alto rendimiento, juegos y hardware integrado. Personalmente estoy agradecido. Aprendí sobre punteros, ya que la transición a las referencias de Java (un concepto similar a los punteros) fue muy fácil y no me perdí cuando vi mi primera NullPointerException (que en realidad debería llamarse NullReferenceException, pero estoy divagando) .

Recomendaría aprender sobre el concepto de punteros, ya que aún sustentan una gran cantidad de estructuras de datos, etc. Luego, elija un idioma en el que le guste trabajar, sabiendo que si surge algo como un NPE, sabrá cuál es realmente pasando.

    
respondido por el Martijn Verburg 05.09.2011 - 11:45
0

Esta es la verdad objetiva:

Algunos idiomas admiten el acceso directo a la memoria (punteros), otros no. Hay buenas razones para cada caso.

  1. Como alguien dijo aquí, en los días de C, la administración automática de la memoria no era tan complicada como lo es hoy. Y la gente se había acostumbrado, de todos modos. Los buenos programadores en aquel entonces tenían una comprensión mucho más profunda de los programas de computadora que de nuestra generación (tengo 21 años). Han estado usando tarjetas perforadas y días de espera durante un tiempo de compilación en el mainframe. Probablemente sabían por qué existía cada bit en su código.

  2. La ventaja obvia de lenguajes como C es que te permiten tener un mejor control sobre tu programa. ¿Cuándo realmente lo necesita , en estos días? Solo cuando está creando aplicaciones de infraestructura, como programas relacionados con el sistema operativo y entornos de tiempo de ejecución. Si solo desea desarrollar un software bueno, rápido, robusto y confiable, entonces la administración automática de la memoria suele ser su mejor opción.

  3. El hecho es que el acceso directo a la memoria se ha abusado principalmente en el curso de la historia del desarrollo de software. La gente había estado creando programas que perdían memoria y en realidad eran más lentos debido a la asignación de memoria redundante (en C es fácil y común ampliar el espacio de memoria virtual del proceso para cada asignación).

  4. En estos días, las máquinas virtuales / tiempos de ejecución hacen un trabajo mucho mejor que el 99% de los programadores al asignar y liberar memoria. Además de eso, le permiten una mayor flexibilidad en el flujo que desea que tenga su programa, porque (en su mayoría) no está ocupado liberando la memoria asignada en el momento y lugar correctos.

  5. En cuanto al conocimiento. Creo que es admirable que los programadores sepan cómo se implementan los entornos en los que programan. No necesariamente a los detalles más pequeños, sino al panorama general.

Creo que saber cómo funcionan los punteros (como mínimo) es interesante. Igual que saber cómo se implementa el polimorfismo. De dónde proviene su proceso, y cómo. Estas son cosas que siempre me han interesado, personalmente. Honestamente puedo decir que me han hecho un mejor programador, pero no puedo decir que sean una necesidad educativa para cualquiera que quiera convertirse en un buen programador. En cualquier caso, saber más a menudo te hará mejor en tu trabajo.

  1. La forma en que lo veo, si todo lo que se le pide que haga es crear una aplicación en Java o C # o algo así, entonces debe centrarse en el diseño adecuado y las técnicas de implementación. Código comprobable, código limpio, código flexible. En ese orden.

Porque incluso si no conoces todos los pequeños detalles, alguien que sí lo haga podrá cambiar lo que has creado en algo que simplemente funciona mejor. Y, a menudo, no es un trabajo difícil, una vez que tiene un diseño correcto, limpio y comprobable en su lugar (y eso suele ser la mayor parte del trabajo).

Si fuera un entrevistador que quisiera contratar a alguien para una aplicación de lenguaje de alto nivel, esas serían las cosas en las que estaría más interesado.

El conocimiento de bajo nivel es una ventaja. Es bueno para depurar y ocasionalmente crear soluciones ligeramente mejores. Te hace una persona interesante, profesionalmente. Te otorga un cierto respeto en tu lugar de trabajo.

Pero en el mundo de hoy, no es un requisito sagrado.

    
respondido por el Yam Marcovic 11.09.2011 - 20:52
-1

Para la mayoría de los propósitos prácticos en los idiomas OO de alto nivel, entender las referencias es suficiente, no es necesario entender cómo estos lenguajes implementan las referencias en términos de punteros.

Hay muchos más enfoques multi-paradigma funcionales y modernos que valoraría mucho más alto que ser capaz de hacer aritmética de punteros de fantasía, digamos, escriba la función de copia de cadena optimizada número 1000 probablemente con un rendimiento peor que String.copy de su biblioteca estándar de cualquier manera.

Recomendaría aprender mucho más diferente, primero los conceptos de nivel superior, y diversificarse para aprender idiomas de diferentes diseños para ampliar su horizonte antes de intentar especializarse en cosas cercanas al hardware.

A menudo veo intentos totalmente fallidos de micro-optimizar el servlet web o un código similar para obtener un 5% de ganancia, cuando el almacenamiento en caché (memorización), la optimización de SQL, o simplemente la optimización de la configuración del servidor web puede producir el 100% o más con poco esfuerzo. Jugar con los punteros es optimización prematura en la mayoría de los casos.

    
respondido por el Jürgen Strobel 05.09.2011 - 12:35
-1

Definitivamente, necesitamos tener un concepto completo de puntero, si realmente quieres ser un buen programador. El motivo del concepto Pointer fue un acceso directo a su valor, que se vuelve más eficiente y efectivo con limitaciones de tiempo ...

También, ahora, considerando las aplicaciones móviles, que tienen una memoria muy limitada, necesitamos usarla con mucho cuidado para que su funcionamiento sea muy rápido con la respuesta del usuario ... Entonces, para este propósito, necesitamos una referencia directa al valor ...

Considere los dispositivos de Apple, o el lenguaje Objective C, que funciona totalmente solo con el concepto de puntero. Toda la variable declarada en el Objetivo C tiene puntero. Debes ir a través de la wiki de Objective C

    
respondido por el DShah 11.09.2011 - 19:06

Lea otras preguntas en las etiquetas