¿Cuál es una buena explicación para los punteros? [cerrado]

72

En sus propios estudios (por su cuenta o para una clase), ¿tuvo un momento de "ah ja" cuando finalmente comprendió los indicadores? ¿Tiene una explicación que utiliza para los programadores principiantes que parece particularmente efectiva?

Por ejemplo, cuando los principiantes primeros punteros de encuentro en C, puede ser que sólo tiene que añadir &s y *s hasta que se compila (como yo mismo hice una vez). Tal vez fue una imagen, o un ejemplo muy bien motivado, que hizo que los punteros hicieran "clic" para usted o su estudiante. ¿Qué fue y qué probaste antes de que eso no parecía funcionar? ¿Hubo algún requisito previo (p. Ej., Estructuras o matrices)?

En otras palabras, ¿qué era necesario para comprender el significado de &sy *cuando podía usarlos con confianza? Aprender la sintaxis y la terminología o los casos de uso no es suficiente, en algún momento la idea necesita ser internalizada.


Actualización: realmente me gustan las respuestas hasta ahora; por favor sigan viniendo Aquí hay muchas perspectivas geniales, pero creo que muchas son buenas explicaciones / consignas para nosotros mismos después de haber internalizado el concepto. Estoy buscando los contextos y circunstancias detallados cuando te di cuenta.

Por ejemplo:

Solo entendí un poco los punteros sintácticamente en C. Escuché a dos de mis amigos explicar los punteros a otro amigo, quien preguntó por qué structse pasaba un puntero. El primer amigo habló sobre cómo necesitaba ser referenciado y modificado, pero fue solo un breve comentario del otro amigo donde me golpeó: "También es más eficiente". Pasar 4 bytes en lugar de 16 bytes fue el cambio conceptual final que necesitaba.

Macneil
fuente
16
Método 'Shotgun': tira * s en todas partes hasta que funcione.
Michael K
15
@ Michael: Sí, buena suerte con eso.
Robert Harvey
8
Esta pregunta surge poco después al comienzo de cada semestre en SO. La última encarnación está aquí: stackoverflow.com/questions/4118647/…
Tim Post
10
¿Cuál es una buena explicación para los punteros? Brian Kernhigan y Dennis Ritchie odian a los ingenieros de software.
Adam Crossland el
3
"Hizo clic" para mí después de pasar un tiempo en código de máquina de un solo paso en el depurador. Sí, estaba familiarizado con los conceptos básicos de la arquitectura de computadoras: aprendí el ensamblaje en Commodore 64, y x86 ASM fue bastante sencillo después de eso. Así que ya conocía el concepto de una "dirección", simplemente no entendía cómo se asignaba a las construcciones sintácticas de C.
zvrba

Respuestas:

25

Diagrama de memoria como una cuadrícula

Por lo general, lo que hago es representar la memoria como una "cuadrícula", de modo que pueda inventar direcciones, resaltar diferentes espacios de memoria y escribir en los valores de las celdas (o incluso más, sus representaciones binarias) y vincular los punteros en la memoria a los valores que apuntar a. (Y aún así mencionar que es una simplificación).

Por lo general, es un momento "ohhhh" para la mayoría de mis estudiantes.

Símbolo malabares

Luego, cuando se trata de hacer que dejen de olvidar cómo usar & y *, es muy simple: presentarlo de la misma manera que hacen cálculos matemáticos o físicos. Si divide una distancia en km por un tiempo en horas, obtendrá una velocidad en km / h. Lo que hay dentro debe estar afuera. Sencillo.

printf al rescate

Hacer solo unos pocos ejemplos básicos que representen visualmente lo que usted explicó con estos los reconfortará en lo que ellos creen que entendieron, o les dará la oportunidad de decir "ah, no entiendo este".

Ser extenso

Cubra los punteros para tipos simples y asegúrese de que entiendan la diferencia entre el direccionamiento y el tamaño de un tipo de datos, luego estructuras, matrices y niveles múltiples.

Luego, inicie la aritmética del puntero.


Anexo: Recursión

Usualmente explico la recursión de manera similar, usando una representación visual. Pídales que impriman el alfabeto usando una función prefabricada que escribe un solo carácter y luego pídales que lo impriman en orden inverso simplemente cambiando dos líneas.

Por lo general, hay un "¿qué demonios ...?" momento, y cuando agrega solo otro parámetro a su printf para imprimir valores numéricos y sangrar los pasos, se convierte en un suspiro de alivio.


Alternativas: el modelo Play-Doh y las tazas de agua

De hecho, tuve algunos compañeros de trabajo en una universidad que les mostraron a los estudiantes un video explicando punteros y accesos a la memoria usando play-doh paste. Fue increíblemente inteligente y bien hecho, aunque nunca usé esa técnica yo mismo, excepto para estudiantes muy jóvenes interesados ​​en comprender la programación (pero generalmente aquellos que no los guiaría hacia un idioma usando punteros demasiado temprano). Básicamente, usando pequeñas bolas de play-doh que puede adjuntar a otras bolas más grandes de play-doh que representan espacios de memoria, y que puede combinar para unirlas (como en una estructura de datos enlazada) o fusionarlas (como en un contiguo espacio de memoria). El uso de diferentes colores para los espacios de memoria señalados y los punteros también ayudan. Pero sigo pensando que lo de la memoria como una cuadrícula funciona mejor, como puede mostrar claramente que el apuntar es realmente una cuestión de "direccionamiento", como en un "mapa / cuadrícula". Mientras que el modo Play-doh todavía los confunde al pensar que las cosas realmente "se tocan" entre sí en la memoria.

La cosa de la Copa del Agua fue utilizada directamente por un colega también, pero no sé si se le ocurrió. Fue un enfoque interesante, pero noté que muchos estudiantes quedaron desconcertados por la explicación. Algo parecido a la técnica DevSolo's Coffee Cup . Pero creo que en realidad es engañoso, ya que hace que los estudiantes confundan contenedores, estructuras de datos, punteros y matrices. Supongo que podría ser un enfoque interesante explicar las matrices al principio, pero no me quedaría mucho tiempo.

haylem
fuente
Wow, gracias por la recompensa. Me alegro de que la respuesta fue apreciada.
haylem
Dibujarlo: | eso suena como una buena enseñanza!
Spooks
80

Alguien mucho más sabio de lo que dije una vez:

La monja Wu Jincang le preguntó al Sexto Patriach Huineng: "He estudiado el sutra Mahaparinirvana durante muchos años, pero hay muchas áreas que no entiendo del todo. Por favor, ilumíneme".

El patriaca respondió: "Soy analfabeto. Por favor, léanme los caracteres y tal vez pueda explicar el significado".

La monja dijo: "Ni siquiera puedes reconocer a los personajes. ¿Cómo puedes entender el significado?"

"La verdad no tiene nada que ver con las palabras. La verdad puede compararse con la luna brillante en el cielo. Las palabras, en este caso, pueden compararse con un dedo. El dedo puede señalar la ubicación de la luna. Sin embargo, el dedo no es el luna. Para mirar la luna, es necesario mirar más allá del dedo, ¿verdad? "

Frank Shearar
fuente
13
+1 para desreferenciar la luna. +1 para el koan, si pudiera.
Tim Post
14
¿Cuál es el sonido de la votación de un dedo?
Adam Crossland el
3
@ Adam, eso depende de si estás usando un mouse o un trackpad.
Daniel Joseph el
77
@Frank Fue una gran cita. Aún así, creo que no ayudará a comprender la idea. Especialmente para alguien nuevo en punteros.
Gulshan
11
Esta es una historia hermosa ... pero sospecho que la gente está votando por eso, en lugar de porque explica bien los indicadores.
Kyralessa
46

Encontré que los diagramas fueron muy útiles. Ejemplo:

diagrama de puntero


Este tipo de diagrama me ayudó a ver que los punteros eran su propia variable, pero contenían un valor que era la ubicación de otro objeto, es decir, matriz o cadena. Además, cuando lo hago con lápiz, podría usarlo para trazar mi programa en papel o en una pizarra / pizarra.

Michael K
fuente
44
El valor dentro del "puntero" debe ser 4 o los índices de la matriz (o las direcciones de memoria) deben comenzar desde 0. De lo contrario, ¿cómo puede un puntero que contiene el valor 3 apuntar a la ubicación 4?
MAK
++ Así es exactamente como iba a explicarlo. Empecé en Fortran (¡para bien o para mal!). En Fortran, en aquel entonces, utilizamos matrices paralelas en lugar de matrices de estructuras (no hay nada nuevo ). Si una matriz contenía un índice de "otra fila" en las matrices, la llamamos "puntero", y esto fue emocionante. Hicimos listas vinculadas, árboles, lo que sea.
Mike Dunlavey el
2
Encuentro que los punteros se explican mejor usando imágenes que indican dónde se almacena y flechas para indicar dónde apuntan los punteros.
gablin
32

Cuando "aprendí" por primera vez acerca de los punteros, me sentí empujado a ello. Mi universidad había tomado la decisión mucho tiempo antes de que me inscribiera para centrar el plan de estudios en Java, por lo que cuando mi profesor de Estructuras de datos dio una conferencia sobre C y nos pidió que implementemos una lista XOR con punteros, sentí que me estaba metiendo en algo muy por encima de mi cabeza.

Entendí la definición:

Un puntero es una variable que contiene la dirección de una variable.

Pero todavía no entendía una gran parte del concepto. Mirando hacia atrás, creo que se centró en tres cosas:

  1. ¿Qué es exactamente una ubicación de memoria? (En ese momento no tomé una clase de organización de computadoras)

  2. La sintaxis incómoda (Entonces ... ¿por qué exactamente se define como "int * ip" pero luego me refiero a la variable como "ip"?)

  3. ¿Cómo es exactamente beneficioso almacenar la dirección de una variable en lugar de solo usar la variable?

No fue hasta que compré el libro de K&R y completé todos los problemas que realmente pude entender los consejos. Además del hecho de que durante mucho tiempo completé la clase de Organización de la Computadora (que creo que debería ser necesaria antes de aprender C), parte de ella tuvo que ver con el hecho de que me di cuenta de que los punteros se pueden usar para funciones, matrices, estructuras ... para hacer cosas útiles y no simplemente como almacenamiento para direcciones de variables ordinarias.

Pero mi momento "ajá" fue la forma en que K&R explicó la incómoda sintaxis de definir un puntero simple. Tomé notas a lo largo del libro (en el que reformulo los puntos hechos por el libro en mis propias palabras para profundizar mi comprensión), y este es el que se relaciona con eso:

Un puntero es una variable que contiene una dirección a una variable. Un puntero está definido y desreferenciado (produciendo el valor almacenado en la ubicación de memoria a la que apunta) con el operador '*'; La expresión es mnemónica.

Ex.: 
   int a;      /* Variable 'a' is an integer */

   int *ip;   /* Variable ip is a pointer and dereferencing it gives an integer.
                 In other words, the expression *ip is an int, so ip is a pointer
                 to an int */

Siempre sentí que no podía comprender completamente los conceptos más avanzados de punteros hasta que tuviera algo tan elemental arraigado en mi cabeza. Me había molestado sin cesar después de esa tarea (que no me fue muy bien, por cierto;)) por qué "* ip" no existía justo después de que (pensé que) definía "* ip". Dominar esto es esencial para conceptos más avanzados que involucran punteros, como punteros de función y definiciones más complicadas como esta:

char (*(x())[])()

En general, creo que el concepto de punteros requiere:

  1. Una comprensión básica de cómo se presenta la memoria en una computadora (y qué es la memoria).

  2. Conocimiento de cuán poderosos pueden ser los punteros (uso en el mundo real, no solo otro concepto abstracto que aprenden por el simple hecho de aprender).

  3. Descifrando los jeroglíficos coloquialmente conocidos como "una definición de puntero"

Así que, en general, creo que debería haber al menos 3 "aha" momentos al aprender sobre punteros. Todavía soy estudiante, así que pensé que apreciaría el punto de vista de alguien que todavía está (relativamente) recién aprendiendo el concepto.

Kevin
fuente
+1 para los 3 "¡Ah, ja!" monents. Punteros Groking viene en capas. "Entendí" los puntos durante mucho tiempo antes de
darme
Creo que tiene toda la razón en que una gran parte de "no entender los punteros" en realidad es tropezar con la extraña sintaxis de C. [Piensa: Me pregunto cuán difícil sería asimilar este tipo de sintaxis: PointerTo<int> a]
Benjol
De acuerdo, @Benjol. Me sorprende que la sintaxis int* ipno sea más común. Finalmente comencé a entender los punteros una vez que vi el código que estaba formateado de esta manera. Entonces podría leerlo como "ip is of type int pointer".
Jacob
19

El puntero es un poco como los accesos directos a aplicaciones en su escritorio. Elimine el acceso directo y el objetivo todavía existe. Inicie el acceso directo y el objetivo comienza.

Siempre explico el funcionamiento de esto simplemente creando un archivo txt en mi escritorio y dos accesos directos al archivo. Después de copiar y eliminar los accesos directos, puede ver que las personas entienden la idea detrás de las 'referencias'.

Una vez que el grupo comprende lo básico detrás de los atajos, puede comenzar a explicar los punteros de la forma que desee. Probablemente lo entenderán con bastante facilidad.

Barfieldmv
fuente
Esa no es una mala analogía. Solo unos pocos puntos para agregar para cualquiera que tome esto literalmente como un "enlace duro" siempre apuntará a su objetivo, incluso si cambia de directorio, un puntero apuntará a la memoria original incluso si el objeto ha sido reubicado. Un "enlace rígido" le dirá cuando el objetivo ya no exista, un puntero colgante debe establecerse en NULL.
snmcdonald
Un enlace rígido es como un puntero inteligente contado de referencia
jk.
1
+1. Una de las mejores analogías prácticas para explicar los punteros. Estoy seguro de que los estudiantes obtendrán la idea de inmediato, ya que esta funcionalidad es la más utilizada por todos.
Karthik Sreenivasan
13

Hace 8-10 años, enseñé un curso de introducción "C" en un colegio comunitario. Este siempre fue un tema divertido para explorar. Lo que parecía funcionar mejor, y esto fue después de discutir un par de veces con un compañero de trabajo, fue usar una taza de café y la mano.

Usé la analogía de una taza de café (o una fila de ellos para los arreglos) como una variable (puede contener algo). Luego usé mi mano, que también podía sostener algo o, al extender mi dedo índice para "señalar" una taza de café.

Una mano cercana era nula, un dedo apuntando a mi cabeza (como una pistola simulada) era un puntero que colgaba.

Luego, con algunas demostraciones y viajes a través del depurador, hizo clic con la mayoría.

DevSolo
fuente
3
Ya me has confundido.
kirk.burleson
1
@ Kirk, ¿cómo es eso? déjame ver si puedo aclararlo.
DevSolo
44
++ No hay nada como enseñar para hacerte pensar en estas cosas.
Mike Dunlavey, el
Uno de mis profesores en la universidad hizo algo similar, usando estudiantes (uno de los cuales era "Niel", para reír), en lugar de la taza de café. Señalar con la mano con la mano al público era un puntero colgante, porque podría estar apuntando a cualquier cosa.
Kaz Dragon
2
Un puntero colgante es más como señalar a Neil que obligarlo a abandonar su silla sin cambiar el lugar al que apunta ... luego tratar de seguir ese puntero e interpretar lo que encuentra allí como un Neil, independientemente de quién haya terminado allí.
Jon Purdy
10

Realmente me preocupo bastante cuando escucho la pregunta "¿cómo entendiste los punteros?". Siempre pensé que el concepto era increíblemente simple y una evolución lógica de los lenguajes que proporcionaban un gran poder a los programadores.

Lo que me preocupa es que nunca me resultó difícil entender el concepto de punteros. Entonces, cuando estás aquí "cuándo finalmente lo conseguiste" una y otra vez, comienzas a pensar:

¿Realmente lo entiendo? Tal vez nunca lo hice?

Tal vez la razón por la cual el concepto parece ser complicado, es porque seguimos diciéndoles a todos los que aún no los han encontrado que los punteros son tan difíciles, y aquí hay cientos de formas en que puedes aprender.

Simplemente lanzando esa idea, por supuesto, personalmente, me encanta un buen diagrama y Steve Gibson siempre hace un trabajo fantástico al explicar cualquier cosa .

Marcus Whybrow
fuente
Interesante ... ¿qué idioma usaste en ese momento? Creo que la sintaxis C hace tropezar a mucha gente. Si supieras la asamblea primero, podría ver que esa es una razón. [Por cierto, quiero votar esto, pero llegué a mi límite por hoy.]
Macneil
Curiosamente, no tenía conocimiento de punteros "peligrosos" durante mucho tiempo, trabajando en Python (y Java en la Universidad). Luego tomé un módulo de "métodos orientados a objetos" que usaba C ++ como el lenguaje de elección y me metí directamente allí.
Marcus Whybrow
También creo que comprender cómo se representa un programa en la memoria definitivamente puede ayudar, pero creo que preferiría decir que entender por qué los punteros fueron una adición útil a un lenguaje, es el ángulo más efectivo, ya que usted está experimentando lo mismo proceso como los diseñadores originales.
Marcus Whybrow
+1 No tengo idea de por qué la gente piensa que los punteros son difíciles o misteriosos.
ggambett
Sí, los punteros siempre han sido tan obviamente simples y útiles que no puedo imaginar pensar que hay algo "difícil" en ellos. Odio cuando un profesor de cualquier curso dice "ahora, esto es un poco complicado" porque es muy subversivo. Simplemente enseñe las malditas cosas y deje que los estudiantes decidan por sí mismos si creen que es complicado.
Jon Purdy
7

Nunca tuve muchos problemas con los punteros en C, pero eso puede deberse a que primero tuve que aprender ensamblador. En realidad, fue un alivio no tener que administrar las direcciones por mí mismo. Entonces, tal vez la respuesta (suponiendo que esto es algo que está enseñando) es dar a los estudiantes un lenguaje ensamblador emulado para trabajar. Ellos van a averiguarlo en el proceso de escribir nada más sofisticado que "Hola, mundo".

Larry Coleman
fuente
+1 para adaptar una abstracción más primitiva, en lugar de intentar usar una analogía.
Tipo anónimo el
En mi escuela secundaria, una unidad de Estudios de Computación se dedicó a estudiar una computadora de caja de cerillas , que se puede enseñar desde el pizarrón sin tocar ni involucrar una computadora real.
rwong
@Larry Coleman, Asamblea !!!!!!!!!!! Quiero probarlo antes que C. Por favor, dime dónde comenzar a aprender. Ebooks gratis, PDF gratis? IDE? ¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡Por favor!!!!!!!!!!!!!!!!!!!
Spacez Ly Wang
7

Un puntero es una variable cuyo valor es la dirección de memoria de otra variable.

kirk.burleson
fuente
Elegante, ¿por qué hacerlo más complicado?
Bjarke Freund-Hansen
Si los punteros no parecen inmediatamente intuitivos y útiles, se les ha explicado mal.
Jon Purdy
6

¿Cómo aprendí realmente sobre los punteros? Al escribir un simple compilador de primer año de la universidad.

¿Cómo explicar los punteros en términos simples? Me gusta la analogía (¿fechada?) De un catálogo de biblioteca almacenado en fichas. Cada tarjeta ("puntero") contiene información sobre dónde se encuentra algún libro ("datos"), pero en realidad no contiene el libro en sí. Si modifica la tarjeta ("aritmética de puntero"), todo lo que hace es cambiar el libro al que apunta y no tiene impacto en el libro en sí mismo; solo tenga cuidado de no arruinar la dirección o podría apuntar a un libro inexistente o incluso la biblioteca equivocada. Sin embargo, si sigue la "dirección" en la tarjeta y va a la parte adecuada de la biblioteca ("desreferenciar el puntero"), puede ver / modificar el libro en sí.

Yevgeniy Brikman
fuente
+1 para el recuerdo de mi curso de CS donde tuve exactamente esa explicación
Gary Rowe
Eso es bueno en cierto modo, pero algo engañoso, ya que las cartas en realidad no dicen dónde está el libro. Aún necesita ejecutar un algoritmo de búsqueda orientado a zapatillas. Quizás esto modela mejor una base de datos, haciendo referencia a un objeto almacenado por una clave (número de llamada).
DarenW
+1 La analogía conserva el mismo concepto que el explicado por Barfieldmv pero con un enfoque más real.
Karthik Sreenivasan
5

Asumiré que alguien que va a aprender punteros sabe cuáles son las variables normales y cómo funcionan en C. Ahora, intentemos definir punteros con algunos de sus atributos.

  • También son variables, pero de diferente naturaleza. Suponga que hay dos capas en el espacio variable. Las variables normales de diferentes tipos residen en la capa superior y los punteros en la capa inferior. Como esta figura

    texto alternativo

  • Como sugiere el nombre 'Puntero', los punteros pueden apuntar a algo. Como nuestro dedo puede apuntar a algún objeto. ¿Cuáles son las cosas que señalan? Estas son las variables normales. En resumen, "Los punteros apuntan a variables normales".

  • Al igual que las variables normales, los punteros también son del mismo número de tipos como int, char o float. Y un puntero de un tipo específico puede apuntar solo al mismo tipo de variables.
  • Un puntero puede apuntar a una variable y luego el mismo puntero puede apuntar a otra variable. Solo el tipo debería ser el mismo. Entonces, la asociación de un puntero con alguna variable no es permanente y se puede cambiar.
  • Entonces, ¿cómo se declara un puntero? Casi como las variables normales. Debe preceder el nombre con un asterisco ( *). Me gusta-

    int *pointer;
    
  • Entonces, ¿cómo se asocia un puntero con una variable? Usando el &operador antes de la variable como esta declaración:

    pointer = &variable;
    
  • ¿Cómo se usa un puntero apuntando a una variable? Esto también se hace precediendo el nombre con un asterisco ( *). Entonces se puede usar en lugar de la variable que está señalando ahora.

    *pointer = var1 + var2;
    

    en lugar de

    variable = var1 + var2;
    
  • Ahora, juega con punteros con algo de código. Solo acostúmbrate a estas características de los punteros ahora. Hasta este punto, estamos hablando de lo que hacen los punteros. Una vez que esté de acuerdo con esto, comience a estudiar cómo los punteros apuntan a alguna variable y cómo reaccionan si se les aplican operaciones aritméticas normales. Luego, busque la relación entre punteros y matrices y punteros a punteros.

Eso es todo lo que sugeriré sobre aprender punteros.

Gulshan
fuente
Quería seguir el proceso "primero lo que hace y luego cómo". ¡Abstracción!
Gulshan
5

Editado en apoyo del requisito revisado de la pregunta

Mi camino hacia la comprensión "post-puntero" (si no recuerdo mal) fue así. Tenía una experiencia simple de programación de ensamblaje de cuando todavía estaba jugando con una BBC Micro, así que tuve el concepto de memoria como un montón de cajas (ver más abajo para esto). Esto fue reforzado por el uso de matrices. Sin embargo, estaba entrando en el mundo de C y tuve que lidiar con cadenas y eso significaba punteros. En BASIC esto fue trivial, en ensamblador nunca tuve que trabajar con ellos, y ahora en el clásico C todo es punteros y demás. Ah, pero puedo volver a las matrices con cadenas (terminadas en nulo) como esta:

char s[] = "Hello, world!";
printf("%s",s);

Todo bien, eso es solo una serie de caracteres (8 bits por personaje en mi pequeño mundo) con un carácter cero al final para mostrar dónde termina. El printf simplemente toma esa matriz y la ejecuta, imprimiéndola. Pero, ¿qué pasa si quiero pasar esta cadena a una función?

void print_str(char* p) {
  printf("%s",p);
}

Es lo que dice el manual, pero ¿de qué se trata eso *? Hmm, char * significa "puntero a un char". OK ... me perdiste. Entonces caí en la cuenta de que char * hace p equivalente a s [0]. OK, puedo usar eso, pero todavía no he explicado qué son los punteros. Quiero decir, ¿cómo configuro algunos datos con una de estas cosas? De nuevo al manual ...

char* p = "Hello World!";

Mientras escribo lo anterior, me digo "declare un puntero a un carácter y configúrelo igual a este conjunto de caracteres". De alguna manera, ese puntero elimina la necesidad de una matriz. Supongo que es el compilador haciendo algunas cosas por mí para variar. Entonces, ¿cómo puedo cambiar la matriz con este puntero? Sé que podría usar la versión de matriz

 s[2] = 'L'; 

pero, ¿cuál es el equivalente en "hablar puntero"? A ese manual otra vez ...

*(p+2) = 'L';

Supongo que * simplemente significa "el contenido de la dirección de memoria" y (p+2)es s[2]. Lo que significaba que el puntero p era ... solo ... una ... dirección ... ¡bong!

Que hay el sonido de la iluminación. Repentinamente tiré punteros (fue hace mucho tiempo, nosotros, los viejos, no "asimilamos" hasta más tarde). Fue solo indirección.


Original:

Vale, mi 2c vale:

Imagina que la memoria es un montón de cajas. Cada casilla tiene un número al costado (la dirección). Cada cuadro contiene un número (el contenido). Puede trabajar con estos cuadros de 2 maneras: variables (quiero el contenido del cuadro N), punteros (quiero el contenido del cuadro, lo que sea ​​que esté en el cuadro N ). Los punteros son simplemente indirección.

Y para la gran respuesta que cubre todo lo que necesitará saber, lea esto .

Gary Rowe
fuente
++ Esa es más o menos la forma en que enseñé el tema.
Mike Dunlavey, el
Artículo editado para admitir los requisitos de OP.
Gary Rowe
¿Qué manual usaste para agregar caracteres NUL adicionales al final de tus cadenas?
Rob Gilliam el
@raimesh Una muy antigua (alrededor de 1991). No recuerdo cuál.
Gary Rowe
1991? Eso no es viejo para un manual en lenguaje C: ¡la primera edición de K&R se publicó en 1978! Me intrigó que alguna vez hubo un manual que sugiriera que necesitabas poner \ 0 al final de tus constantes de cadena. (En realidad, mirándolo de nuevo, ¿querías poner \ n?)
Rob Gilliam
4

Consigue unos pequeños bloques de madera.

agregue ganchos de metal a un extremo y ojos de metal al otro.

ahora puedes hacer una lista vinculada en cosas con las que puedes jugar.

Intenta explicar con este accesorio físico. A menudo deseaba tener esto cuando enseñaba consejos a estudiantes de primer año (primer año).

El pequeño gancho de metal es el puntero, el bloque de madera al que apuntaba la cosa.

Desafío a cualquiera a que no lo obtenga después de jugar con los bloques.

Tim Williscroft
fuente
4

Hice mi vida más fácil cuando eliminé toda la pelusa y comencé a tratar el puntero como cualquier otra variable en lugar de una entidad mágica (hace mucho tiempo en el grado 11) ... solo sé 3 cosas:

  1. El puntero es una variable que almacena la dirección de otra variable (o simplemente cualquier dirección).
  2. * se utiliza para obtener el valor en la ubicación de la memoria que está almacenada en la variable del puntero.
  3. & operador da la dirección de una ubicación de memoria.

El resto es azúcar sintáctica y sentido común. Simplemente escriba algunos programas simples de C (como implementar una biblioteca de listas enlazadas) usando punteros para familiarizarse con ellos.

Sridhar Iyer
fuente
2
  1. El puntero puede considerarse como una generalización de un índice en una matriz.
    • Tenga en cuenta que una gran matriz se puede cortar en una serie de matrices más pequeñas, no superpuestas, de tamaño variable. Ahora, estas matrices más pequeñas son lo que generalmente pensamos como matriz. El más grande es el espacio de memoria completo de la computadora. El proceso de cortar matrices más pequeñas se llama asignación de memoria.
  2. Un conjunto de estructuras que están unidas por algunos punteros se puede considerar como un gráfico dirigido .
    • Cada vértice es una variable que puede contener algún valor.
    • Algunas variables son punteros, y cada puntero puede tener exactamente un borde saliente en otra cosa.
    • Las variables que no son punteros no tendrán ningún borde de salida. Podrían tener cualquier número de ventaja entrante.
rwong
fuente
2

No puedo recordar las circunstancias en torno a mis punteros-aha-momento, pero he reajustado retroactivamente la memoria en torno a mi comprensión de una matriz de estilo C. ( arr[3]es decir, es lo mismo que *(arr+3))

Por alguna razón, encuentro inmensamente útil ver los punteros como matrices cada vez que me encuentro con una situación de puntero.

Zaz
fuente
2

Básicamente, @Gary Rowe presentó el modelo correcto. Memoria como un conjunto de cuadros con direcciones (números) en ellos. Cada caja almacena un valor (número).

La idea de un puntero es interpretar el valor en un cuadro como la dirección de otro cuadro. Este valor se usa para referirse a un cuadro específico, por eso se le llama referencia . Por lo tanto, la desreferenciación es el proceso de abrir el cuadro al que se hace referencia.

si ves una variable (cuadro), entonces la declaración

  • vsignifica valor de v, es decir, dame lo que hay en el cuadro
  • *vsignifica desreferenciar el valor de v, es decir, darme lo que está en el cuadro referido por el valor dev
  • &vsignifica referencia v, es decir, dame la dirección en la casilla

Creo que no sirve al propósito de introducir punteros como algo completamente diferente. Fue un concepto difícil de entender para mí cuando era niño. Siempre parecía una magia oscura que nunca entendí realmente, que necesitaba muchos personajes especiales. La primera vez que entendí fue cuando escribí un pequeño juego usando doble indirección en un lenguaje que no tiene aritmética de puntero. Eso me iluminó.

Los punteros son una cuestión de interpretación. Creo que explicar eso hace las cosas mucho más fáciles. Y la aritmética de punteros son operaciones extremadamente simples e intuitivas si se muestra un ejemplo simple con una memoria de 10 variables.

back2dos
fuente
2

La explicación que realmente critiqué fue:

Considere una cuadrícula de la ciudad con diferentes casas construidas en terrenos. En tu mano sostienes un pedazo de papel. En el papel que has escrito:


La casa de David

112 Tan y tan calle.


El trozo de papel (variable de puntero) contiene una dirección que apunta a la casa de David. Cuando quieres decirle a un amigo que eche un vistazo a la casa de David, es mucho más fácil usar el trozo de papel como referencia de la casa que enviar el edificio de dos pisos por correo.

Al igual que con los punteros reales, puede meterse en problemas cuando sigue la dirección en su hoja de papel. David podría haberse mudado y cuando llegas allí solo encuentras un gran agujero en el suelo. En este caso, hubiera sido mejor borrar la dirección en el papel cuando David se mudó o al menos cambiarla por la nueva. También podrías encontrar que vas a la dirección y entras en lo que crees que es la sala de estar de tu amigo David, pero esta vez terminas en una piscina completa de extraños. Alguien más ha usado el espacio en la dirección que tenía para algo completamente diferente.

Por Wiklander
fuente
2

Si desea explicar los punteros, primero debe explicar la memoria. Usualmente hago eso usando papel cuadriculado / papel cuadrado con filas y columnas. Si el "estudiante" entiende la memoria, puede entender qué es una dirección. Si tienes dirección tienes punteros.

Puedes jugar con esta abstracción. Por ejemplo, escriba la dirección (número) de un cuadrado en otro cuadrado. Ahora dibuja una flecha desde el cuadrado del puntero hasta el cuadrado de destino. Ahora sobrescriba el puntero (por ejemplo, increméntelo) y ajuste la flecha. Escriba una dirección en otro cuadrado y deje que el alumno dibuje la flecha ...

Siguiente paso: asigne un nombre a ciertos cuadrados (como el puntero). Ahora puede explicar la desreferenciación. Eso es.

EricSchaefer
fuente
2
Me recuerda a una "computadora" que utilicé antes de que pudiera tener en mis manos una que realmente usaba electrones: el cartón "CARDIACO", creo que se llamaba. Literalmente, escribir números en cuadros numerados para obtener números de otros cuadros numerados. Se fue educativa y nunca he tenido problemas para entender punteros en microprocesadores reales.
DarenW
2

Quizás solo soy yo, pero trabajo bien con analogías. Entonces, digamos que tiene un amigo (función / clase) "Foo", que quiere tener a otra persona (función / clase diferente), "Bar", que se contacte con usted por alguna razón. "Foo" podría llevarte a ver "Bar", pero eso no es conveniente, moviendo a todos esos seres (instancias). Sin embargo, "Foo" podría enviar a "Bar" su número de teléfono (puntero). De esa manera, no importa dónde se encuentre, "Foo" sabe cómo contactarlo sin tener que encontrarlo.

Y, digamos que "Bar" tiene un conocido, "Baz", que también quiere ponerse en contacto con usted. Pero protege su número de teléfono y no quiere que todos lo tengan, "Baz" puede llamar a "Bar" (teléfono como puntero), que luego puede reenviarle la llamada (otro puntero). Y así sucesivamente en la cadena de amigos y amigos de "Baz".

Hugo
fuente
2

Los punteros tienen mucho más sentido si has estudiado lenguaje ensamblador y / o arquitectura de computadora. Creo que si enseño una clase C, comenzaría con un par de semanas de arquitectura para explicar el modelo de memoria y el tipo de instrucciones que el procesador realmente ejecuta.

Barry Brown
fuente
Absolutamente. Cuando se trata de registros y comprende cosas como valores inmediatos y direccionamiento indirecto, todo el concepto de punteros es intuitivo. Aprendí el ensamblaje 6502 y luego el ensamblaje 68K antes de escribir mi primera línea de C, así que cuando me presentaron los punteros, miré el ensamblaje (intermedio) del compilador y era exactamente como se esperaba.
Radian
2

Mi "¡ajá!" momento llegó en este tutorial:

Un tutorial sobre punteros y matrices en C

Para ser exactos, vino en este capítulo: Capítulo 3: Punteros y cadenas

Para ser aún más preciso, vino con esta oración:

El parámetro pasado a Puts () es un puntero, que es el valor de un puntero (ya que todos los parámetros en C se pasan por valor), y el valor de un puntero es la dirección a la que apunta o, simplemente, una dirección .

Cuando leí eso, las nubes se separaron y los ángeles hicieron sonar trompetas.

Como puede ver, cada tutorial o libro de C que leí antes afirmaba que C podía pasar por valor o por referencia, una mentira nefasta. La verdad es que C siempre pasa por valor, pero a veces el valor pasado es una dirección. Dentro del método, se hace una copia de esa dirección, al igual que una copia se haría de un int se ha pasado. Una copia es no hizo del valor al que apunta el puntero. Por lo tanto, al usar el puntero dentro del método, puede acceder al valor original y cambiarlo.

Nunca me convertí en programador de C, pero me convertí en programador de .NET, y los objetos y referencias de objetos funcionan de la misma manera; la referencia al objeto se pasa por valor (y, por lo tanto, se copia), pero el objeto en sí no se copia. He trabajado con muchos programadores que no entienden esto porque nunca aprendieron punteros.

Kyralessa
fuente
1

El truco consiste en explicar que la ubicación de una cosa y la cosa en sí no son lo mismo, al igual que una imagen de una tubería no es una tubería . Cuando mueves una cosa, su ubicación cambia. La ubicación permanece y se puede poner algo más allí.

sal
fuente
1

Un puntero es una nota adhesiva que te dice dónde está algo útil. Contiene la ubicación de la cosa y te dice qué tan grande es la cosa (en C, de todos modos). Entonces, un doble puntero es como una nota adhesiva que dice "Hay un paquete de seis en el refrigerador". Tienes que ir a buscar el paquete de seis para averiguar si es Coca-Cola o Budweiser.

filosodad
fuente
1

Dado el código:

int v=42; // declarando e inicializando una variable simple

int *p = &v; // creando un punto p para la variable v

Lo siguiente se puede decir sobre el código anterior:

int * p // "int puntero p" ... así es como declaras un puntero a una variable de tipo int

*p // "señalado por p" ... esa es la información a la que apunta p, es lo mismo que v.

&v // "dirección de la variable v" ... esto representa el valor literal para p

zener
fuente
1

http://cslibrary.stanford.edu/

Este sitio tiene excelentes tutoriales para aprender punteros y administrar la memoria.

Te sugiero que recorras los aspectos básicos de los punteros, los punteros y la memoria que se dan en el sitio. También puede ver los problemas de las listas vinculadas que figuran en el enlace para fortalecer aún más los conceptos de puntero.

Deovrat Singh
fuente
1

La clave para explicar los punteros es asegurarse de que las personas a las que les está explicando ya comprendan el concepto de memoria. Si bien sería bueno si realmente lo entendieran de bajo nivel, creer que la memoria existe como una matriz masiva y comprender que puede acceder a cualquier posición en la matriz por su ubicación de índice es suficiente.

El siguiente paso, tener el concepto de pasar la ubicación del índice en lugar de copiar toda la memoria tiene sentido para la mayoría de las personas. Y eso es suficiente para que la mayoría de las personas entiendan por qué los punteros son útiles.

El último paso para comprender los punteros es explicar cómo puede pasar como parámetro una ubicación de índice de memoria para el método para almacenar la ubicación de índice donde se almacenan todos los datos. He descubierto que esto puede ser un paso demasiado lejos para que algunas personas lo puedan hacer frente.

Una vez que alguien ha comprendido estos pasos básicos, es sencillo que comprenda que puede encadenar punteros indefinidamente, siempre y cuando realice un seguimiento de cuántas veces necesita buscar direcciones para encontrar el objeto de datos real.

Una vez que alguien ha captado los punteros, lo siguiente que debe comprender rápidamente es la diferencia entre la memoria de montón y la memoria de apilamiento, y por qué los punteros para apilar la memoria son peligrosos cuando se pasan fuera del método.

Michael Shaw
fuente
0

Recuerdo un libro "Rompecabezas en C" o similar, que leí simplemente porque era uno de los pocos libros de programación / informática disponibles en la biblioteca, mi comprensión de C era rudimentaria. Le arrojó una expresión C y le pidió que lo explotara, cada vez más complicado.

Peterchen
fuente
0

Cuando estaba en la universidad, mi profesor tenía algunas diapositivas de PowerPoint realmente ordenadas que representaban un punto como una variable separada por sí mismo con una flecha a una ubicación de memoria (representada como una matriz) y cuando estábamos haciendo Listas Vinculadas, lo hacía paso a paso. paso a paso, que muestra cuándo cambia la flecha, cuándo se desreferencia el puntero, etc., no había forma de que uno no pudiera entenderlo en un par de minutos. El concepto en sí es realmente fácil, pero hacerlo bien o aplicarlo en programas prácticos requiere más práctica.

chiurox
fuente
0

Antes de hacer eso, explico que en la programación "todo usa memoria" y la asignación de variables (estáticas) en la memoria. También explicaré qué es una dirección de memoria y la relación entre el espacio de memoria, la dirección de memoria y las variables.

Finalmente, explico que hay tipos de datos enteros y variables, tipos de datos de cadena y variables ... y así sucesivamente, hasta explicar que hay un tipo de datos especial que almacena direcciones de memoria, que tiene un valor vacío como 0 o "", llamado nulo .

Y, finalmente, variables asignadas dinámicamente a través del uso de punteros.

umlcat
fuente