¿Por qué el maestro C Dennis Ritchie introdujo 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 son el concepto que hace que C sea poderoso y sobresaliente y hace que C siga compitiendo con lenguajes más modernos. Entonces, ¿por qué eliminaron los punteros en los idiomas 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 utiliza ningún concepto de puntero) y muchas personas como veo ahora (mis amigos) eligen estos lenguajes ignorando C ya que 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:
Las computadoras anteriores eran demasiado lentas y no estaban optimizadas.
El uso de punteros permite acceder a una dirección directamente y esto ahorra tiempo en lugar de hacer una copia de ella en las llamadas a funciones.
La seguridad es significativamente peor usando punteros, y es por eso que Java y C # no los incluyeron.
Estos y algo más de lo que encontré. Todavía necesito algunas respuestas valiosas. Eso sería muy apreciado.
Respuestas:
En aquellos días, los desarrolladores estaban trabajando mucho más cerca del metal. C fue esencialmente un reemplazo de nivel superior para el ensamblaje, que está casi tan cerca del hardware como 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 grandes daños si se usan descuidadamente. Además, el uso directo de punteros abre la posibilidad a muchos problemas de seguridad, que no eran un problema en aquel 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 volvió más y más importante desde entonces. Así que hoy en día los lenguajes de nivel superior están diseñados conscientemente para evitar punteros de memoria sin procesar.
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 completos, por lo que, en teoría, todo lo que es posible en un idioma, es posible en todos. Solo piense en lo que sucede cuando se compila y ejecuta un fragmento de código VB.Net o Java: eventualmente, se traduce (o se asigna a) código de máquina, porque eso es lo único que la máquina entiende. En lenguajes compilados como C y C ++, en realidad puede obtener el cuerpo completo del 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 VM, 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í está allí en algún lugar, dentro de las profundidades 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 idioma específico. Ningún desarrollador sensato comenzaría a escribir una aplicación web en conjunto :-) 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, generalmente en C.
Entonces, para llegar a la pregunta,
El concepto detrás de los punteros es indirección . Este es un concepto muy importante y, en mi humilde opinión, todo buen programador debería comprenderlo en cierto nivel. Incluso si alguien está trabajando únicamente con lenguajes de nivel superior, la indirección y las referencias siguen siendo importantes. No comprender esto significa no poder utilizar toda una clase de herramientas muy potentes, lo que limita seriamente la capacidad de resolución de problemas a largo plazo.
Entonces, mi respuesta es sí, si quieres convertirte en un programador verdaderamente bueno, también debes comprender los punteros (así como la recursividad: este es el otro obstáculo típico para los desarrolladores en ciernes). Es posible que no necesite comenzar con esto: no creo que C sea óptimo como primer idioma hoy en día. Pero en algún momento uno debería familiarizarse con la indirección. Sin ella, nunca podremos entender cómo funcionan realmente las herramientas, bibliotecas y marcos que estamos utilizando. Y un artesano que no entiende cómo funcionan sus herramientas es muy limitado. Es justo que uno también lo entienda en lenguajes de programación de alto nivel. Una buena prueba de fuego es implementar correctamente una lista doblemente vinculada: si puede hacerlo en su idioma favorito, puede afirmar que entiende la indirección lo suficientemente bien.
Pero si no fuera por otra cosa, deberíamos hacerlo para aprender a respetar a los programadores de antaño que lograron construir cosas increíbles utilizando las herramientas ridículamente simples que tenían (en comparación con lo que tenemos ahora). Todos estamos parados sobre los hombros de gigantes, y nos hace bien reconocer esto, en lugar de pretender que somos nosotros mismos los gigantes.
fuente
Creo que necesitas diferir.
Java y otros lenguajes de nivel superior no eliminaron punteros. Lo que hicieron fue eliminar la aritmética de puntero simple.
De hecho, Java todavía permite una aritmética de puntero protegida y restringida : el acceso a la matriz. En la antigua C simple, el acceso a la matriz no es más que desreferenciar. Es una notación diferente, un azúcar sintáctico, si quieres, para comunicar claramente lo que estás haciendo.
Aún así,
array[index]
es equivalente a*(array+index)
. Por eso también es equivalente a,index[array]
aunque supongo que algunos compiladores de C podrían darte una advertencia, si haces eso.Como corolario,
pointer[0]
es equivalente a*pointer
. Esto se debe simplemente a que 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 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, comprobará si ese índice está o no dentro de los límites de la matriz que asignó originalmente. Si no, arrojará una excepción.
Ahora la ventaja del enfoque de Java es que no tiene código, que simplemente escribe bytes arbitrarios en ubicaciones de memoria arbitrarias. Esto mejora la seguridad y también la seguridad, porque si no puede verificar los desbordamientos del búfer y demás, el tiempo de ejecución lo hará por usted.
La desventaja de esto es que es simplemente menos poderoso. Es posible realizar una programación segura de la memoria en C. Es imposible beneficiarse de la velocidad y las posibilidades de programación insegura en Java.
En realidad, no hay nada difícil sobre punteros o aritmética de punteros. Normalmente se explican de manera complicada, mientras que todo un puntero es un índice de una matriz gigante (su espacio de memoria), todo lo que hace referencia a un valor es darle al índice dónde encontrarlo, todo lo que hace la desreferenciación es buscar El valor en un índice dado. (Esto está un poco simplificado, porque no tiene en cuenta que los valores son de diferente tamaño en la memoria, dependiendo de su tipo. Pero eso es un detalle circunstancial, en lugar de una parte del concepto real)
En mi humilde opinión, todos en nuestro trabajo deberían ser capaces de entender eso, o simplemente están en el campo equivocado.
fuente
back2dos
tenía razón la primera vez, ya que(array + index)
ya tiene en cuenta el tamaño de los objetos (en C).array[index]
, y eso es todo*(array+index)
. Si desea mostrar cómo el compilador hace las cosas internamente, puede hablar explícitamente sobre bytes o dar el ensamblado.El concepto de punteros es importante en el cuerpo de conocimiento general de programación de computadoras. Comprender el concepto es bueno para ser programadores o programadores de cualquier idioma, incluso si el idioma no lo admite directamente.
Los punteros tienen su uso en estructuras de datos (listas vinculadas) y diseño de bases de datos (clave externa).
Lenguajes como VB y C # pueden pasar datos por "referencia" a métodos, que pueden considerarse como un tipo de puntero.
Comprender dónde se asignan los datos en la memoria (pila vs. montón) sigue siendo importante para la eficiencia de los algoritmos.
Aprender los conceptos básicos correctamente es importante en mi opinión.
fuente
std::sort
,std::partition
,std::find
, Etc. Trabajan con los punteros, y trabajan con los objetos que actúan como punteros (iteradores). Y trabajan sobre cualquier colección general; listas vinculadas, matrices dinámicas,deque
s, árboles o cualquier otro tipo de colección definida por el usuario. No puedes ese tipo de abstracción sin punteros.¡¡¡Si si SI SI y si!!!
Si no conoce los conceptos básicos, NUNCA podrá resolver los problemas realmente difíciles, extraños, difíciles y complicados que se le presenten.
Y si comprende los conceptos básicos realmente bien, es MUCHO más comercializable en el mercado laboral.
Trabajé una vez con un tipo 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 blanca educándolo. Eso me abrió los ojos. No tenía IDEA sobre tantas cosas básicas.
Sepa todo lo que pueda.
fuente
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 modificarNewList
. Cuando intenté imprimir ambas listas, ambas eran iguales, ya queNewList
solo era un punteroOldList
y no una copia, por lo que en realidad estaba cambiandoOldList
todo el tiempo. No me llevó mucho tiempo darme cuenta de eso, pero algunos de mis compañeros de clase no fueron tan rápidos y tuvieron que explicar por qué está sucediendo esto.Ejemplo:
Y, por supuesto, el resultado es así:
Saber cómo usarlos no es tan importante, ¡pero comprenderlos es crucial!
fuente
NewList
era solo un puntero aOldList
" - para ser precisos, ambosNewList
yOldList
solo eran punteros, refiriéndose al mismoList
objeto.b
ya no tiene referencias y ahora es basura.Apunta el concepto! = Apunta la aritmética! = Apunta la sintaxis
Lo primero siempre es importante, si necesita (y lo hace) comprender la copia profunda / superficial, pasar por referencia / pasar por valor, etc. Las otras dos solo importan si su idioma del día le permite usarlas.
fuente
a=[1,2]; b=a; a.append(3)
ambosa
y los dos harán referenciab
al mismo objeto[1,2,3]
sin saber cosas como en C, eli
elemento th de una matriz puede ser referenciado porarr[i]
oi[arr]
como ambos lo son*(arr+i)
. Prefiero cuando el idioma no se dejai[arr]
usar.Porque los punteros son un mecanismo muy poderoso que se puede usar de muchas maneras.
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 prudente presentarlos temprano. La razón es que se usan para tantos propósitos diferentes, que es difícil saber como principiante por qué está usando un puntero en una circunstancia particular.
Aquí hay una lista incompleta para qué se utilizan los punteros:
new T
)struct T { T* next; /* ... */ };
)for (T* p = &a[0]; p != &a[0] + n; ++p) { ... }
)T* new_pointer = existing_pointer;
)T* pointer_to_base = pointer_to_derived;
)mutate(&object);
)if (p) { /* ... */ }
)Tenga en cuenta que el uso de un mecanismo único 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.
fuente
¿Por qué? Puede escribir un sistema enorme con el diseñador de formularios y el generador de código. ¿No es suficiente? (ironía)
Y ahora en serio, los punteros no son una parte crucial de la programación en muchas áreas, pero permiten a las personas comprender cómo funcionan los elementos internos. Y si no tenemos a nadie que entienda cómo funcionan las partes internas, habrá una situación en la que SQL2020, Windows 15 y Linux 20.04 se escribirán en una máquina virtual recolectada de basura que ejecuta más de 30 capas de abstracción, con código generado a través de IDE, en JavaScript .
Esto definitivamente no es lo que quiero ver.
Entonces sí, definitivamente tienen que hacerlo.
fuente
Ni Java ni C # eliminaron punteros, tienen referencias que son casi las mismas. Lo que se eliminó es la aritmética de puntero, que se puede omitir en un curso introductorio.
No se podría realizar 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 dinámica de memoria sin ellos).
Considere lo siguiente en C ++ y Java, y supongo que no es muy diferente en C #:
aClass *x = new aClass();
aClass x = new aClass();
Realmente no hay demasiada diferencia entre punteros y referencias, ¿verdad?
La aritmética del puntero debe evitarse a menos que sea necesario y cuando se programe con modelos de alto nivel, por lo que no hay muchos problemas allí.
fuente
El programador profesional debe dominar los punteros.
Las personas que desean conocer la programación deben aprender sobre su existencia e implicaciones, pero no necesariamente usarlas.
Las personas que desean resolver problemas personales a través de la programación (como yo, que usa muchos scripts de Python) podrían ignorarlos.
Bueno, esa es mi opinión ...; o)
fuente
Los punteros de dirección variable son un caso específico del concepto más generalizado de indirección. La indirecta se usa en la mayoría de los lenguajes modernos (¿todos?) En muchos constructos, como delegados y devoluciones de llamada. Comprender el concepto de indirección le permite saber cuándo y cómo utilizar mejor estas herramientas.
fuente
Absufreakinglutely SÍ ! Todos los que programan deben comprender los punteros y la indirección.
Los punteros son cómo se realiza una gran cantidad de acceso a datos en todos los idiomas. Los punteros son una característica de hardware de todos los microprocesadores. Los lenguajes de alto nivel como Java, VB & C # esencialmente bloquean el acceso directo a los punteros de los usuarios del lenguaje con referencias. Las referencias se refieren a objetos a través del esquema de gestión de memoria del lenguaje (podría ser un puntero con metadatos o simplemente un número para una tabla de memoria, por ejemplo).
Comprender cómo funcionan los punteros es fundamental para comprender 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 cual las matrices comienzan en el índice cero es porque las matrices son en realidad una forma abreviada de aritmética de puntero. Sin aprender cómo funcionan los punteros, muchos programadores principiantes no obtienen matrices.
La línea 2 en la aritmética del puntero sería:
¡Sin comprender los punteros, uno no puede entender la administración de memoria, la pila, el montón o incluso las matrices! Además, uno debe 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 entender que las computadoras realmente funcionan .
fuente
Creo que todo se reduce al hecho de que la necesidad de lidiar con los punteros disminuyó a medida que los programadores lidiaron menos con el hardware directo en el que se estaban ejecutando. Por ejemplo, asignar una estructura de datos de lista vinculada de una manera que se ajuste perfectamente a la secuencia de módulos de memoria de 640 bytes que tenía el hardware especializado.
Tratar con punteros manualmente puede ser propenso a errores (lo que lleva a pérdidas de memoria y código explotable) y lleva mucho tiempo hacerlo bien. Entonces, Java y C #, etc. ahora administran su memoria y sus punteros a través de sus máquinas virtuales (VM). Esto podría decirse que es menos eficiente que usar C / C ++ sin formato, aunque las máquinas virtuales están mejorando constantemente.
C (y C ++) siguen siendo lenguajes ampliamente utilizados, especialmente en los espacios de computación de alto rendimiento, juegos y hardware integrado. Estoy personalmente agradecido de haber aprendido acerca de los 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 realmente debería llamarse NullReferenceException, pero estoy divagando) .
Aconsejaría aprender sobre el concepto de punteros, ya que todavía sustentan muchas estructuras de datos, etc. Luego, elija un idioma en el que le encanta trabajar, sabiendo que si surge algo como un NPE, ya sabe lo que realmente está sucediendo. .
fuente
Esta es la verdad objetiva:
Algunos idiomas admiten acceso directo a memoria (punteros), otros no. Hay buenas razones para cada caso.
Como alguien dijo aquí, en los días de C, la administración automática de memoria no era tan elaborada como lo es hoy. Y la gente ya estaba acostumbrada, de todos modos. Los buenos programadores en ese 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 algún tiempo de compilación en el mainframe. Probablemente sabían por qué existía cada parte de su código.
La ventaja obvia de lenguajes como C es que le permiten tener un control más fino sobre su programa. ¿Cuándo lo necesitas en estos días? Solo cuando crea 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, la administración de memoria automática es su mejor opción.
El hecho es que el acceso directo a la memoria se ha abusado principalmente en el transcurso del historial de 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 extender el espacio de memoria virtual del proceso para cada asignación individual).
En estos días, las máquinas virtuales / tiempos de ejecución hacen un trabajo mucho mejor que el 99% de los programadores para asignar y liberar memoria. Además de eso, le permiten una flexibilidad adicional en el flujo que desea que tenga su programa, porque (en su mayoría) no está ocupado liberando memoria asignada en el momento y lugar correctos.
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. Lo mismo que saber cómo se implementa el polimorfismo. De dónde obtiene su proceso su memoria y cómo. Estas son cosas que siempre me han interesado personalmente. Honestamente puedo decir que me han convertido en 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.
Porque incluso si no conoce todos los pequeños detalles, alguien que lo haga podrá cambiar lo que haya creado en algo que simplemente funcione mejor. Y eso a menudo no es un trabajo difícil, una vez que tiene un diseño adecuado, limpio y comprobable (y eso suele ser la mayor parte del trabajo).
Si fuera un entrevistador que buscara contratar a alguien para una aplicación de lenguaje de alto nivel, esas serían las cosas que más me interesarían.
El conocimiento de bajo nivel es una ventaja. Es bueno para depurar y ocasionalmente crear soluciones ligeramente mejores. Te hace una persona interesante, profesionalmente. Le otorga algo de respeto en su lugar de trabajo.
Pero en el mundo de hoy, no es un requisito sagrado.
fuente
Para la mayoría de los propósitos prácticos en idiomas OO de alto nivel, la comprensión de referencias es suficiente, realmente no necesita comprender cómo estos idiomas implementan referencias en términos de punteros.
Hay muchos enfoques multi-paradigmáticos más funcionales y modernos que valoraría mucho más que poder hacer una aritmética de puntero elegante para decir, escribir la función de copia de cadena optimizada número 1000 que probablemente tenga un rendimiento peor que String.copy de su biblioteca estándar de ninguna manera.
Aconsejaría aprender primero conceptos mucho más diferentes y de mayor nivel, 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 código similar para obtener un 5% de ganancia, cuando el almacenamiento en caché (memorización), la optimización de SQL o solo el ajuste de la configuración del servidor web puede producir el 100% o más con poco esfuerzo. Jugar con punteros es una optimización prematura en la mayoría de los casos.
fuente
Definitivamente, necesitamos tener un concepto completo de puntero, si realmente quieres ser un buen programador. La razón del concepto de puntero fue un acceso directo a su valor que se vuelve más eficiente y efectivo con limitaciones de tiempo ...
Además, hoy en día, considerando las aplicaciones móviles, que tienen una memoria muy limitada, necesitamos usarla con mucho cuidado para que su operación sea muy rápida 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. Necesitas pasar por la wiki del Objetivo C
fuente