A partir de la cantidad de preguntas publicadas aquí, está claro que las personas tienen algunos problemas fundamentales para entender los punteros y la aritmética de punteros.
Tengo curiosidad por saber por qué. Realmente nunca me han causado problemas importantes (aunque aprendí por primera vez sobre ellos en el Neolítico). Para poder escribir mejores respuestas a estas preguntas, me gustaría saber qué es lo que las personas encuentran difícil.
Entonces, si estás luchando con punteros, o si recientemente te "entendiste", ¿cuáles fueron los aspectos de los punteros que te causaron problemas?
Respuestas:
Sospecho que la gente está profundizando demasiado en sus respuestas. Realmente no se requiere una comprensión de la programación, las operaciones reales de la CPU o la administración de memoria a nivel de ensamblaje.
Cuando estaba enseñando, descubrí que los siguientes agujeros en la comprensión de los estudiantes son la fuente más común de problemas:
La mayoría de mis alumnos pudieron comprender un dibujo simplificado de un trozo de memoria, generalmente la sección de variables locales de la pila en el ámbito actual. En general, ayudar a dar direcciones ficticias explícitas a los distintos lugares.
Supongo que, en resumen, estoy diciendo que si quieres entender los punteros, tienes que entender las variables y lo que realmente son en las arquitecturas modernas.
fuente
Cuando comencé a trabajar con ellos, el mayor problema que tuve fue la sintaxis.
son todos iguales.
pero:
¿Por qué? porque la parte "puntero" de la declaración pertenece a la variable y no al tipo.
Y luego desreferenciar la cosa usa una notación muy similar:
Excepto cuando realmente necesitas obtener un puntero ... ¡entonces usas un ampersand!
¡Hurra por la consistencia!
Luego, aparentemente solo para ser imbéciles y demostrar cuán inteligentes son, muchos desarrolladores de bibliotecas usan punteros a punteros a punteros, y si esperan una variedad de esas cosas, ¿por qué no simplemente pasar un puntero a eso también? .
para llamar a esto, necesito la dirección de la matriz de punteros a punteros a punteros de ints:
En seis meses, cuando tenga que mantener este código, pasaré más tiempo tratando de descubrir qué significa todo esto que reescribiendo desde cero. (sí, probablemente me equivoqué con la sintaxis; ha pasado un tiempo desde que hice algo en C. Lo extraño un poco, pero luego soy un poco massoquista)
fuente
La comprensión adecuada de los punteros requiere conocimiento sobre la arquitectura de la máquina subyacente.
Muchos programadores de hoy no saben cómo funciona su máquina, al igual que la mayoría de las personas que saben conducir un automóvil no saben nada sobre el motor.
fuente
Cuando se trata de punteros, las personas que se confunden están ampliamente en uno de los dos campos. He estado (¿estoy?) En ambos.
La
array[]
multitudEsta es la multitud que directamente no sabe cómo traducir de la notación de puntero a la notación de matriz (o ni siquiera sabe que están relacionados). Aquí hay cuatro formas de acceder a los elementos de una matriz:
La idea aquí es que acceder a las matrices a través de punteros parece bastante simple y directo, pero de esta manera se pueden hacer un montón de cosas muy complicadas e inteligentes. Algunos de los cuales pueden dejar a los programadores experimentados de C / C ++ desconcertados, y mucho menos a los novatos sin experiencia.
El
reference to a pointer
ypointer to a pointer
multitudEste es un gran artículo que explica la diferencia y que mencionaré y robaré un código de :)
Como un pequeño ejemplo, puede ser muy difícil ver exactamente lo que el autor quería hacer si te encuentras con algo como esto:
O, en menor medida, algo como esto:
Entonces, al final del día, ¿qué resolvemos realmente con todo este galimatías? Nada.
Esta complejidad y la aparente intercambiabilidad (en negrita) con referencias, que a menudo es otra advertencia de los punteros y un error de los recién llegados, dificulta la comprensión de los punteros. También es importante entender, por el amor de finalización, que los punteros a referencias son ilegales en C y C ++ para confundir razones que tengan en
lvalue
-rvalue
semántica.Como se mencionó en una respuesta anterior, muchas veces solo tendrás estos programadores que piensan que están siendo inteligentes al usarlos
******awesome_var->lol_im_so_clever()
y la mayoría de nosotros probablemente somos culpables de escribir tales atrocidades a veces, pero simplemente no es un buen código, y ciertamente no es mantenible .Bueno, esta respuesta resultó ser más larga de lo que esperaba ...
fuente
Culpo personalmente a la calidad de los materiales de referencia y a las personas que enseñan; La mayoría de los conceptos en C (pero especialmente los punteros) simplemente se enseñan mal. Sigo amenazando con escribir mi propio libro en C (titulado The Last Thing The World Needs Is Another Book on The C Programming Language ), pero no tengo el tiempo ni la paciencia para hacerlo. Así que me quedo aquí y lanzo citas aleatorias del Estándar a las personas.
También está el hecho de que cuando C se diseñó inicialmente, se suponía que entendía la arquitectura de la máquina a un nivel bastante detallado solo porque no había forma de evitarla en su trabajo diario (la memoria era muy escasa y los procesadores eran muy lentos) tenías que entender cómo lo que escribiste afectó el rendimiento).
fuente
Hay un gran artículo que apoya la idea de que los punteros son difíciles en el sitio de Joel Spolsky: The Perils of JavaSchools .
[Descargo de responsabilidad: no soy un enemigo de Java per se .]
fuente
La mayoría de las cosas son más difíciles de entender si no se basa en el conocimiento que está "debajo". Cuando enseñé CS se hizo mucho más fácil cuando comencé a mis alumnos a programar una "máquina" muy simple, una computadora decimal simulada con códigos de operación decimales cuya memoria consistía en registros decimales y direcciones decimales. Pondrían programas muy cortos para, por ejemplo, agregar una serie de números para obtener un total. Luego lo darían un paso para ver lo que estaba sucediendo. Podrían mantener presionada la tecla "enter" y verla correr "rápido".
Estoy seguro de que casi todos en SO se preguntan por qué es útil ser tan básico. Olvidamos lo que fue no saber programar. Jugar con una computadora de juguete de este tipo establece conceptos sin los cuales no se puede programar, como las ideas de que la computación es un proceso paso a paso, que utiliza un pequeño número de primitivas básicas para desarrollar programas y el concepto de memoria variables como lugares donde se almacenan los números, en los que la dirección o el nombre de la variable es diferente del número que contiene. Hay una distinción entre el momento en que ingresa al programa y el momento en que se "ejecuta". Considero que aprender a programar cruza una serie de "obstáculos", como programas muy simples, luego bucles y subrutinas, luego matrices, luego E / S secuenciales, luego punteros y estructura de datos.
Finalmente, al llegar a C, los indicadores son confusos, aunque K&R hizo un muy buen trabajo al explicarlos. La forma en que los aprendí en C fue saber leerlos, de derecha a izquierda. Como cuando veo
int *p
en mi cabeza, digo "p
señala a unint
". C fue inventado como un paso adelante del lenguaje ensamblador y eso es lo que me gusta de él: está cerca de ese "terreno". Los punteros, como cualquier otra cosa, son más difíciles de entender si no tienes esa base.fuente
No recibí punteros hasta que leí la descripción en K&R. Hasta ese momento, los punteros no tenían sentido. Leí un montón de cosas en las que la gente decía "No aprendas consejos, son confusos y te harán daño en la cabeza y te causarán aneurismas", así que me alejé por mucho tiempo y creé este aire innecesario de concepto difícil. .
De lo contrario, sobre todo lo que pensé fue, ¿por qué querrías una variable por la que tienes que pasar por los aros para obtener el valor, y si querías asignarle cosas, tenías que hacer cosas extrañas para obtener valores? en ellas. Todo el punto de una variable es algo para almacenar un valor, pensé, así que por qué alguien quería complicarlo estaba más allá de mí. "Entonces, ¿con un puntero tienes que usar el
*
operador para obtener su valor? ¿Qué tipo de variable tonta es esa?" , Pensé. No tiene sentido, sin juego de palabras.La razón por la que fue complicado fue porque no entendí que un puntero era la dirección de algo. Si explica que es una dirección, que es algo que contiene una dirección a otra cosa y que puede manipular esa dirección para hacer cosas útiles, creo que podría aclarar la confusión.
Una clase que requería usar punteros para acceder / modificar puertos en una PC, usar aritmética de punteros para abordar diferentes ubicaciones de memoria y observar códigos C más complicados que modificaron sus argumentos me desilusionó de la idea de que los punteros eran, bueno, inútiles.
fuente
Aquí hay un ejemplo de puntero / matriz que me dio pausa. Suponga que tiene dos matrices:
Y su objetivo es copiar el contenido de uint8_t del destino de origen usando memcpy (). Adivina cuál de los siguientes logra ese objetivo:
La respuesta (Spoiler Alert!) Es TODAS ellas. "destination", "& destination" y "& destination [0]" tienen el mismo valor. "& destino" es un tipo diferente que los otros dos, pero sigue siendo el mismo valor. Lo mismo ocurre con las permutaciones de "fuente".
Como comentario aparte, personalmente prefiero la primera versión.
fuente
sizeof(source)
, porque sisource
es un puntero,sizeof
no será lo que quieres. A veces (no siempre) escribosizeof(source[0]) * number_of_elements_of_source
solo para mantenerme alejado de ese error.Debería comenzar diciendo que C y C ++ fueron los primeros lenguajes de programación que aprendí. Comencé con C, luego hice C ++ en la escuela, mucho, y luego volví a C para hablarlo con fluidez.
Lo primero que me confundió acerca de los punteros al aprender C fue lo simple:
Esta confusión se debió principalmente a haber sido introducida al uso de referencias a una variable para argumentos OUT antes de que los punteros me fueran presentados correctamente. Recuerdo que omití escribir los primeros ejemplos en C para Dummies porque eran demasiado simples solo para nunca tener el primer programa que escribí para trabajar (muy probablemente debido a esto).
Lo que era confuso sobre esto era lo que
&ch
realmente significaba y por quéstr
no lo necesitaba.Después de familiarizarme con eso, recuerdo haber estado confundido sobre la asignación dinámica. En algún momento me di cuenta de que tener punteros a los datos no era extremadamente útil sin una asignación dinámica de algún tipo, así que escribí algo como:
para tratar de asignar dinámicamente algo de espacio. No funcionó. No estaba seguro de que funcionaría, pero no sabía cómo podría funcionar.
Más tarde aprendí acerca de
malloc
ynew
, pero realmente me parecieron generadores de memoria mágica. No sabía nada sobre cómo podrían funcionar.Algún tiempo después, otra vez me enseñaron la recursión (lo había aprendido por mi cuenta antes, pero ahora estaba en clase) y pregunté cómo funcionaba bajo el capó, dónde estaban almacenadas las variables separadas. Mi profesor dijo "en la pila" y muchas cosas me quedaron claras. Había escuchado el término antes y había implementado pilas de software antes. Había escuchado a otros referirse a "la pila" mucho antes, pero lo había olvidado.
Alrededor de este tiempo también me di cuenta de que usar matrices multidimensionales en C puede ser muy confuso. Sabía cómo funcionaban, pero era tan fácil enredarse en eso que decidí tratar de evitar usarlos siempre que pudiera. Creo que el problema aquí era principalmente sintáctico (especialmente al pasar o devolverlos de las funciones).
Como estaba escribiendo C ++ para la escuela durante el próximo año o dos, obtuve mucha experiencia en el uso de punteros para estructuras de datos. Aquí tuve un nuevo conjunto de problemas: mezclar punteros. Me gustaría que varios niveles de punteros (cosas como
node ***ptr;
) me hicieran tropezar. Quitaría la referencia de un puntero la cantidad incorrecta de veces y eventualmente recurriría a calcular cuántas*
necesitaba por prueba y error.En algún momento aprendí cómo funcionaba el montón de un programa (más o menos, pero lo suficientemente bueno como para que ya no me mantuviera despierto por la noche). Recuerdo haber leído que si mira unos pocos bytes antes de que
malloc
regrese el puntero que en cierto sistema, puede ver cuántos datos se asignaron realmente. Me di cuenta de que el código enmalloc
podría pedir más memoria del sistema operativo y esta memoria no era parte de mis archivos ejecutables. Tener una idea funcional decente de cómomalloc
funciona es realmente útil.Poco después de esto, tomé una clase de asamblea, que no me enseñó tanto sobre punteros como la mayoría de los programadores probablemente piensan. Me hizo pensar más sobre en qué ensamblado podría traducirse mi código. Siempre había tratado de escribir código eficiente, pero ahora tenía una mejor idea de cómo hacerlo.
También tomé un par de clases donde tuve que escribir un poco de lisp . Al escribir lisp, no estaba tan preocupado por la eficiencia como en C. Tenía muy poca idea de a qué se podría traducir este código si se compilaba, pero sabía que parecía utilizar muchos símbolos (variables) locales con nombre. Las cosas son mucho más fáciles. En algún momento escribí un código de rotación de árbol AVL en un poco de ceceo, que me costó mucho escribir en C ++ debido a problemas con el puntero. Me di cuenta de que mi aversión a lo que pensaba que eran variables locales en exceso había impedido mi capacidad de escribir eso y varios otros programas en C ++.
También tomé una clase de compiladores. Mientras estaba en esta clase, pasé al material avanzado y aprendí sobre la asignación única estática (SSA) y las variables muertas, lo cual no es tan importante, excepto que me enseñó que cualquier compilador decente hará un trabajo decente al tratar con variables que son ya no se usa Ya sabía que más variables (incluidos los punteros) con los tipos correctos y los buenos nombres me ayudarían a mantener las cosas claras en mi cabeza, pero ahora también sabía que evitarlas por razones de eficiencia era aún más estúpido de lo que me dijeron mis profesores menos optimistas. yo.
Entonces, para mí, conocer un poco sobre el diseño de memoria de un programa me ayudó mucho. Pensar en lo que significa mi código, tanto simbólicamente como en el hardware, me ayuda. El uso de punteros locales que tienen el tipo correcto ayuda mucho. A menudo escribo código que se parece a:
así que si arruino un tipo de puntero, por el error del compilador queda muy claro cuál es el problema. Si lo hice:
y si hay algún tipo de puntero incorrecto allí, el error del compilador sería mucho más difícil de resolver. Me sentiría tentado a recurrir a cambios de prueba y error en mi frustración, y probablemente empeoraría las cosas.
fuente
Mirando hacia atrás, había cuatro cosas que realmente me ayudaron a comprender finalmente los punteros. Antes de esto, podía usarlos, pero no los entendía completamente. Es decir, sabía que si seguía los formularios, obtendría los resultados que deseaba, pero no entendía completamente el "por qué" de los formularios. Me doy cuenta de que esto no es exactamente lo que ha pedido, pero creo que es un corolario útil.
Escribir una rutina que tomara un puntero a un entero y modificara el entero. Esto me dio las formas necesarias sobre las cuales construir modelos mentales de cómo funcionan los punteros.
Asignación de memoria dinámica unidimensional. Descubrir la asignación de memoria 1-D me hizo comprender el concepto del puntero.
Asignación de memoria dinámica bidimensional. Descubrir la asignación de memoria en 2-D reforzó ese concepto, pero también me enseñó que el puntero en sí mismo requiere almacenamiento y debe tenerse en cuenta.
Diferencias entre variables de pila, variables globales y memoria de montón. Descubrir estas diferencias me enseñó los tipos de memoria a los que apuntan / se refieren los punteros.
Cada uno de estos elementos requería imaginar lo que estaba sucediendo en un nivel inferior: construir un modelo mental que satisficiera cada caso que se me ocurriera. Tomó tiempo y esfuerzo, pero valió la pena. Estoy convencido de que para comprender los punteros, debe construir ese modelo mental sobre cómo funcionan y cómo se implementan.
Ahora volvamos a su pregunta original. Según la lista anterior, había varios elementos que tuve dificultades para comprender originalmente.
fuente
Tuve mi "momento de puntero" trabajando en algunos programas de telefonía en C. Tuve que escribir un emulador de intercambio AXE10 usando un analizador de protocolos que solo entendía el clásico C. Todo dependía de conocer punteros. Traté de escribir mi código sin ellos (hey, estaba "pre-puntero" me cortó un poco) y fallé por completo.
La clave para entenderlos, para mí, fue el operador & (dirección). Una vez que entendí que
&i
significaba la "dirección de i", entonces entendí que*i
significaba "el contenido de la dirección señalada por i" llegó un poco más tarde. Cada vez que escribía o leía mi código, siempre repetía lo que significaba "&" y lo que significaba "*" y eventualmente llegué a usarlos intuitivamente.Para mi vergüenza, me forzaron a usar VB y luego Java, por lo que mi conocimiento de punteros no es tan agudo como lo era antes, pero me alegro de haber sido "post-puntero". Sin embargo, no me pidas que use una biblioteca que requiera que comprenda * * p.
fuente
&i
es la dirección y*i
el contenido, ¿cuál esi
?La principal dificultad con los punteros, al menos para mí, es que no comencé con C. Empecé con Java. Toda la noción de punteros era realmente extranjera hasta un par de clases en la universidad donde se esperaba que conociera C. Entonces, me enseñé los conceptos básicos de C y cómo usar los punteros en su sentido más básico. Incluso entonces, cada vez que me encuentro leyendo el código C, tengo que buscar la sintaxis del puntero.
Entonces, en mi experiencia muy limitada (1 año en el mundo real + 4 en la universidad), los indicadores me confunden porque nunca he tenido que usarlo realmente en otra cosa que no sea un aula. Y puedo simpatizar con los estudiantes que ahora comienzan CS con JAVA en lugar de C o C ++. Como dijiste, aprendiste punteros en la era 'neolítica' y probablemente lo has estado usando desde entonces. Para nosotros, las personas más nuevas, la noción de asignar memoria y hacer aritmética de punteros es realmente extraña porque todos estos lenguajes lo han abstraído.
PD: Después de leer el ensayo de Spolsky, su descripción de 'JavaSchools' no se parecía en nada a lo que pasé en la universidad de Cornell ('05 -'09). Tomé las estructuras y la programación funcional (sml), los sistemas operativos (C), los algoritmos (lápiz y papel) y una gran cantidad de otras clases que no se enseñaron en Java. Sin embargo, todas las clases introductorias y electivas se realizaron en Java porque tiene valor no reinventar la rueda cuando intentas hacer algo más nivelado que implementar una tabla hash con punteros.
fuente
void foo(Clazz obj) { obj = new Clazz(); }
es un no-op, mientras quevoid bar(Clazz obj) { obj.quux = new Quux(); }
muta el argumento ...Aquí hay una no respuesta: use cdecl (o c ++ decl) para resolverlo:
fuente
Añaden una dimensión adicional al código sin un cambio significativo en la sintaxis. Piensa sobre esto:
Sólo hay una cosa a cambio:
a
. Puedes escribira = 6
y los resultados son obvios para la mayoría de las personas. Pero ahora considere:Hay dos cosas
a
que son relevantes en diferentes momentos: el valor real dea
, el puntero y el valor "detrás" del puntero. Puedes cambiara
:... y
some_int
todavía está en algún lugar con el mismo valor. Pero también puede cambiar lo que señala:Hay una brecha conceptual entre
a = 6
, que solo tiene efectos secundarios locales, y*a = 6
, que podría afectar un montón de otras cosas en otros lugares. Mi punto aquí es que no , que el concepto de direccionamiento indirecto es de por sí difícil, pero que debido a que se puede hacer tanto en lo inmediato, local cona
o indirecta con la cosa*a
... que podría ser lo que confunde a la gente.fuente
Había programado en c ++ durante aproximadamente 2 años y luego me convertí a Java (5 años) y nunca miré hacia atrás. Sin embargo, cuando recientemente tuve que usar algunas cosas nativas, descubrí (con asombro) que no había olvidado nada sobre los punteros e incluso los encuentro fáciles de usar. Este es un fuerte contraste con lo que experimenté hace 7 años cuando traté de comprender el concepto. Entonces, ¿supongo que entender y gustar es una cuestión de madurez de programación? :)
O
Los punteros son como andar en bicicleta, una vez que descubres cómo trabajar con ellos, no hay que olvidarlo.
En general, difícil de entender o no, la idea del puntero es muy educativa y creo que todos los programadores deben entenderla, independientemente de si programa en un idioma con punteros o no.
fuente
Los punteros son difíciles debido a la indirección.
fuente
Los punteros (junto con algunos otros aspectos del trabajo de bajo nivel) requieren que el usuario quite la magia.
A la mayoría de los programadores de alto nivel les gusta la magia.
fuente
Los punteros son una forma de tratar la diferencia entre un identificador de un objeto y un objeto en sí. (ok, no necesariamente objetos, pero sabes a qué me refiero, así como dónde está mi mente)
En algún momento, probablemente tengas que lidiar con la diferencia entre los dos. En el lenguaje moderno de alto nivel, esto se convierte en la distinción entre copia por valor y copia por referencia. De cualquier manera, es un concepto que a menudo es difícil de entender para los programadores.
Sin embargo, como se ha señalado, la sintaxis para manejar este problema en C es fea, inconsistente y confusa. Eventualmente, si realmente intentas entenderlo, un puntero tendrá sentido. Pero cuando comienzas a lidiar con punteros a punteros, y así sucesivamente hasta la náusea, se vuelve realmente confuso para mí y para otras personas.
Otra cosa importante para recordar acerca de los punteros es que son peligrosos. C es el lenguaje de un maestro programador. Asume que sabes qué diablos estás haciendo y, por lo tanto, te da el poder de realmente arruinar las cosas. Si bien algunos tipos de programas aún deben escribirse en C, la mayoría de los programas no, y si tiene un lenguaje que proporcione una mejor abstracción de la diferencia entre un objeto y su identificador, le sugiero que lo use.
De hecho, en muchas aplicaciones modernas de C ++, a menudo ocurre que cualquier aritmética de puntero requerida se encapsula y se abstrae. No queremos que los desarrolladores hagan aritmética de punteros por todas partes. Queremos una API centralizada y bien probada que haga aritmética de punteros en el nivel más bajo. Hacer cambios a este código debe hacerse con mucho cuidado y pruebas exhaustivas.
fuente
Creo que una razón por la cual los punteros en C son difíciles es porque combinan varios conceptos que no son realmente equivalentes; sin embargo, debido a que todos se implementan utilizando punteros, las personas pueden tener dificultades para desenredar los conceptos.
En C, los punteros están acostumbrados a, entre otras cosas:
En C definirías una lista vinculada de enteros como este:
El puntero solo está allí porque esta es la única forma de definir una estructura de datos recursiva en C, cuando el concepto realmente no tiene nada que ver con un detalle de tan bajo nivel como las direcciones de memoria. Considere el siguiente equivalente en Haskell, que no requiere el uso de punteros:
Bastante sencillo: una lista está vacía o se forma a partir de un valor y el resto de la lista.
Así es como puede aplicar una función
foo
a cada carácter de una cadena en C:A pesar de utilizar también un puntero como iterador, este ejemplo tiene muy poco en común con el anterior. Crear un iterador que puede incrementar es un concepto diferente de definir una estructura de datos recursiva. Ningún concepto está especialmente vinculado a la idea de una dirección de memoria.
Aquí hay una firma de función real que se encuentra en glib :
Whoa! Eso es bastante bocado
void*
. Y todo es solo para declarar una función que itera sobre una lista que puede contener cualquier tipo de cosa, aplicando una función a cada miembro. Compárelo con cómomap
se declara en Haskell:Eso es mucho más sencillo:
map
es una función que toma una función que convierte unaa
ab
, y la aplica a una lista dea
's para producir una lista deb
' s. Al igual que en la función Cg_list_foreach
,map
no necesita saber nada en su propia definición sobre los tipos a los que se aplicará.Para resumir:
Creo que los punteros en C serían mucho menos confusos si las personas aprendieran primero sobre estructuras de datos recursivas, iteradores, polimorfismo, etc., como conceptos separados, y luego aprendieran cómo se pueden usar los punteros para implementar esas ideas en C , en lugar de combinar todos estos conceptos juntos en un solo tema de "punteros".
fuente
c != NULL
su ejemplo de "Hola mundo" ... quiere decir*c != '\0'
.Creo que requiere una base sólida, probablemente desde el nivel de la máquina, con introducción a algunos códigos de máquina, ensamblaje y cómo representar elementos y estructura de datos en la RAM. Toma un poco de tiempo, algo de tarea o práctica para resolver problemas, y algo de pensamiento.
Pero si una persona conoce idiomas de alto nivel al principio (lo cual no tiene nada de malo: un carpintero usa un hacha. Una persona que necesita dividir el átomo usa otra cosa. Necesitamos personas que sean carpinteros, y tenemos personas que estudian átomos) y A esta persona que conoce un lenguaje de alto nivel se le da una introducción de 2 minutos a los punteros, y luego es difícil esperar que comprenda la aritmética de punteros, punteros a punteros, matriz de punteros a cadenas de tamaño variable y matriz de matriz de caracteres, etc. Una base sólida de bajo nivel puede ayudar mucho.
fuente
El problema que siempre he tenido (principalmente autodidacta) es el "cuándo" usar un puntero. Puedo entender la sintaxis para construir un puntero, pero necesito saber en qué circunstancias se debe usar un puntero.
¿Soy el único con esta mentalidad? ;-)
fuente
Érase una vez ... Teníamos microprocesadores de 8 bits y todos escribieron en conjunto. La mayoría de los procesadores incluían algún tipo de direccionamiento indirecto utilizado para tablas de salto y núcleos. Cuando aparecieron los lenguajes de nivel superior, agregamos una capa delgada de abstracción y los llamamos punteros. Con los años nos hemos alejado cada vez más del hardware. Este no es necesariamente algo malo. Se llaman idiomas de nivel superior por una razón. Cuanto más me pueda concentrar en lo que quiero hacer en lugar de los detalles de cómo se hace, mejor.
fuente
Parece que muchos estudiantes tienen un problema con el concepto de indirección, especialmente cuando se encuentran con el concepto de indirección por primera vez. Recuerdo que cuando era estudiante, de los más de 100 estudiantes de mi curso, solo un puñado de personas realmente entendía los consejos.
El concepto de indirección no es algo que usamos a menudo en la vida real y, por lo tanto, es un concepto difícil de entender inicialmente.
fuente
Recientemente tuve el momento de hacer clic con el puntero y me sorprendió haberlo encontrado confuso. Era más que todos hablaban tanto de eso, que supuse que estaba ocurriendo algo de magia oscura.
La forma en que lo obtuve fue esto. Imagine que todas las variables definidas tienen espacio de memoria en tiempo de compilación (en la pila). Si desea un programa que pueda manejar archivos de datos grandes como audio o imágenes, no querría una cantidad fija de memoria para estas estructuras potenciales. Así que espera hasta el tiempo de ejecución para asignar una cierta cantidad de memoria para mantener estos datos (en el montón).
Una vez que tenga sus datos en la memoria, no querrá copiar esos datos en todo su bus de memoria cada vez que desee ejecutar una operación en él. Supongamos que desea aplicar un filtro a sus datos de imagen. Tiene un puntero que comienza en la parte frontal de los datos que ha asignado a la imagen, y una función se ejecuta a través de esos datos, cambiándolos en su lugar. Si no supiera lo que estamos haciendo, probablemente terminaría haciendo duplicados de datos, mientras los ejecutaba a través de la operación.
¡Al menos así lo veo yo en este momento!
fuente
Hablando como un novato en C ++ aquí:
El sistema de puntero tardó un tiempo en digerir no necesariamente por el concepto sino por la sintaxis de C ++ en relación con Java. Algunas cosas que encontré confusas son:
(1) Declaración variable:
vs.
vs.
y aparentemente
es una declaración de función y no una declaración de variable. En otros idiomas, básicamente hay una sola forma de declarar una variable.
(2) El ampersand se usa de diferentes maneras. Si esto es
entonces el & a es una dirección de memoria.
OTOH, si es
entonces el & a es un parámetro pasado por referencia.
Aunque esto puede parecer trivial, puede ser confuso para los nuevos usuarios: vengo de Java y Java, un lenguaje con un uso más uniforme de los operadores.
(3) Relación matriz-puntero
Una cosa que es un poco frustrante de comprender es que un puntero
puede ser un puntero a un int
o
puede ser una matriz para un int
Y luego, para complicar aún más las cosas, los punteros y la matriz no son intercambiables en todos los casos y los punteros no se pueden pasar como parámetros de la matriz.
Esto resume algunas de las frustraciones básicas que tuve con C / C ++ y sus punteros, que en mi opinión, se agrava en gran medida por el hecho de que C / C ++ tiene todas estas peculiaridades específicas del lenguaje.
fuente
Personalmente no entendí el puntero incluso después de mi graduación y después de mi primer trabajo. Lo único que sabía es que lo necesita para listas enlazadas, árboles binarios y para pasar matrices a funciones. Esta era la situación incluso en mi primer trabajo. Solo cuando comencé a dar entrevistas, entiendo que el concepto de puntero es profundo y tiene un uso y potencial tremendos. Luego comencé a leer K&R y escribir mi propio programa de prueba. Todo mi objetivo fue impulsado por el trabajo.
En este momento descubrí que los indicadores no son realmente malos ni difíciles si se les enseña de una buena manera. Desafortunadamente, cuando aprendo C en la graduación, nuestro maestro no era consciente del puntero, e incluso las tareas usaban menos punteros. En el nivel de posgrado, el uso del puntero es realmente solo para crear árboles binarios y listas vinculadas. Esta idea de que no necesita una comprensión adecuada de los punteros para trabajar con ellos, mata la idea de aprenderlos.
fuente
Punteros ... ja ... todo sobre el puntero en mi cabeza es que da una dirección de memoria donde los valores reales de cualquiera sea su referencia ... así que no hay magia al respecto ... si aprendes algo de ensamblaje no tendrías tantos problemas para aprender cómo funcionan los punteros ... vamos chicos ... incluso en Java todo es una referencia ...
fuente
El principal problema que las personas no entienden es por qué necesitan punteros. Porque no tienen claro el apilamiento y el montón. Es bueno comenzar desde un ensamblador de 16 bits para x86 con un modo de memoria pequeña. Ayudó a muchas personas a hacerse una idea de la pila, el montón y la "dirección". Y byte :) Los programadores modernos a veces no pueden decirle cuántos bytes necesita para direccionar el espacio de 32 bits. ¿Cómo pueden hacerse una idea de los punteros?
El segundo momento es la notación: declaras el puntero como *, obtienes la dirección como & y esto no es fácil de entender para algunas personas.
Y lo último que vi fue un problema de almacenamiento: entienden el montón y la pila, pero no pueden tener una idea de "estática".
fuente