<div dir="ltr">Hola Javier,<br><div class="gmail_extra"><br><div class="gmail_quote">2013/1/22 Javier <span dir="ltr"><<a href="mailto:javiersalvadormarco@gmail.com" target="_blank">javiersalvadormarco@gmail.com</a>></span><br>


<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Buenas noches chicos,<br>
<br>
Este es mi primer mensaje en esta maravilla de comunidad que nos ayuda a perfeccionar nuestras habilidades en el mundo de la programación, así que antes de nada, ¡muchas gracias por todo!<br>
<br></blockquote><div><br></div><div>Bienvenido a nuestra lista de correo-e y a este "mundillo" de la programación.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


Ahora voy al grano y os expongo mi pregunta, que va relacionada con lo que más me cuesta de entender en el mundo de la programación: los punteros.<br>
<br></blockquote><div><br></div><div>Eso nos pasa a todos cuando vemos este tema, tanto si es la primera vez como la quinta, décima, etc.; incluso para los programadores veteranos.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


Parece que después de mucho machacar el tema he conseguido entender de forma más o menos fiable los punteros que apuntan a funciones u objetos, pero cuando hablamos de punteros que apuntan a punteros o arrays la cosa se me atraganta. Este es el ejemplo </blockquote>

<div><br></div><div>No debería ser tan diferente de lo que ya conoces. Al fin y al cabo, un tipo de puntero sigue siendo un tipo de dato; y una dirección de memoria sigue siendo un valor - en este caso, entero - que podemos guardar en una variable y realizar ciertas operaciones con ella.</div>

<div><br></div><div>Ahora bien, entiendo que quizá tengas dudas en cuanto al uso que puedas dar a punteros a punteros.</div><div><br></div><div>[CORTE]</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


Entiendo que lo que os he marcado como 1 es la inicialización de un puntero, el f, que va a apuntar a la dirección de memoria de otro puntero, el cual todavía falta por crear.<br>
<br></blockquote><div><br></div><div>Bueno, para este tema, es mejor hablar con claridad, por lo que tendremos que ser muy cuidadosos con la terminología que usemos.</div><div><br></div><div>float **f;<br>
<br>es una declaración y definición de la variable 'f'.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


En la parte marcada como 2, reservamos 10 posiciones de memoria a las que apuntará f, habiendo en cada una de ellas un puntero. Si no estoy equivocado, f en este momento podrá recoger el valor de cada uno de los punteros que hay, pudiendo moverse a través de sus direcciones de memoria para obtener su valor: Ejemplo f[0] recogerá el valor que apunte el puntero de la array 0. ¿Es así?<br>



<br></blockquote><div><br></div><div>Creo que lo has dicho correctamente, pero insisto que hay que expresarse con cuidado, en estos temas. 'f[0]' guarda un valor de tipo 'float *'; es decir, sirve para guardar una dirección de memoria.</div>

<div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
Aquí me gustaría hacer una pregunta sobre el tema, y es por qué no se utilizaría para extraer el valor real el parámetro *f[0] si lo que queremos es obtener un valor y no una dirección de memoria. Esto me cuesta un poco de ver, ya que con los punteros que apuntan a objetos se hace de esa forma y con arrays he visto que no.<br>



<br></blockquote><div><br></div><div>Se puede hacer, pero como queremos crear arrays de arrays, sería un tanto incoherente ver algo así:<br><br>*f[0] = 3.12f;</div><div>f[0][1] = -.4127f;<br></div><div>
<div>f[0][2] = 9901231857.2f;</div></div><div>...</div><div><br></div><div>Ciertamente, podríamos usar * para acceder a todos los demás elementos así,<br></div><div><br></div><div><div>*f[0] = 3.12f;</div>
<div>*(f[0]+1) = -.4127f;<br></div><div>*(f[0]+2) = 9901231857.2f;</div><div>...</div><div><br></div></div><div>Sin embargo, es más legible usar [], y además nos ahorramos escribir tres operaciones: *, (), y +.</div>
<div><br></div><div>De todas formas, a estas alturas del programa, no podríamos - o mejor dicho no deberíamos - acceder al puntero en 'f[0]', porque no contiene inicialmente ningún valor válido ni deseado; o sea, contiene "basura".</div>

<div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
Pasamos a la parte marcada como 3. Si esto lo entiendo bien, en este momento vamos creando en cada una de las 10 aposiciones en las que teníamos un puntero, un array de 10 floats. Para acceder a estas posiciones bastará con poner por ejemplo: f[3][3], donde el primer corchete desplazaría el puntero que hemos creado en el punto 1, y el segundo corchete los que hemos creado en el 2. ¿Es correcto?<br>



<br></blockquote><div><br></div><div>Sí y no.</div><div><br></div><div>Vamos creando varios arrays de 10 'float'. Guardamos la dirección de memoria del comienzo de cada array en cada puntero del array que creamos en (2). Al aplicar 'f[3]', estamos realizando el siguiente cálculo:<br>

<br>dir1 = f + 3*sizeof(float**);</div><div><br></div><div>Si 'f' guarda como valor la dirección de memoria de 32 bits (4 bytes) de 0x55AAEE00, entonces tenemos,</div><div><br></div><div>dir1 = 0x55AAEE00 + 3 * 4 = 0x55AAEE0C</div>

<div><br></div><div>y obtenemos su valor, que es una dirección de memoria. Digamos que es 0x99FFBB00. Esta dirección de memoria es el comienzo del array que creamos en la cuarta iteración del bucle 'for' en (3), que vendría a ser esta sentencia:<br>

<br>f[3] = new float[10];</div><div><br></div><div>Al aplicar 'f[3][3]', estamos haciendo un cálculo similar al anterior:<br><br>dir2 = f[3] + 3*sizeof(float*);</div><div><br></div><div>por lo que obtendremos,</div>

<div><br></div><div>dir2 = 0x99FFBB0C</div><div><br></div><div>y el valor guardado en tal dirección de memoria, que podría ser: -8.123f.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


Parte 4. Aquí mi duda radica en el porqué hemos de crear un bucle para liberar todas las posiciones de memoria, si después realizamos la operación 5:  delete[] f. Supongo que esto es un fallo de concepto mío a la hora de entender la reserva de memoria, ya que yo me imaginaba que al hacer    f = new float *[10] reservamos una cantidad de memoria, y después al hacer el bucle   for(n = 0; n < 10; n++) f[n] = new float[10] fragmentábamos parte de esa memoria para asignarla a cada una de las nuevas arrays de floats. Supongo que he mezclado churros con melindras y que cada vez que se utiliza el new se reserva memoria distinta.<br>



<br></blockquote><div><br></div><div>El operador 'new[]' simplemente se comunica con el sistema operativo (S.O.) para pedir que se le adjudique un bloque contiguo de memoria a este programa. Por lo tanto, cada vez que realicemos la operación: new[], estamos pidiendo otro bloque de memoria. Sería problemático si todas las adjudicaciones se basaren en el mismo bloque de memoria. Recuerda que el S.O. no sabe nada de las "intenciones" de los programas que se ejecutarán bajo su control. Si un programa requiere usar un recurso compartido de memoria para sus fines, entonces es la responsabilidad del programa gestionarlo. De hecho, C++ sí acepta esta forma de crear nuevos objetos a partir de memoria existente, usando el operador: 'new()' o incluso 'new[]()', para un array.</div>

<div><br></div><div>Cada 'new[]' provoca una adjudicación nueva de un array, lo cual implica que tendremos diferentes direcciones de memoria al comienzo de cada array. En nuestro ejemplo, hemos usado 'new[]' 11 veces, por lo que debemos usar 'delete[]' 11 veces; y por tanto la regla de: un 'delete[]' por cada 'new[]'.</div>

<div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
Muchísimas gracias por vuestra ayuda chicos. Soy programador de PL/SQL y el mundo orientado a objetos me gusta, pero también me vuelve loco.<br>
<br></blockquote><div><br></div><div>Viendo que eres programador de SQL, realmente este tema de punteros no debería ser conceptualmente difícil para ti, ya que usas el mismo mecanismo a la hora de diseñar - y de programar - bases de datos relacionales. Como ya sabes, al diseñar el esquema de una tabla, lo típico es mantener una columna a modo de identificador como un número entero. Este mismo identificador aparecerá en el esquema de otra tabla. A la hora de usar las tablas, usaremos ese mismo identificador para relacionarlas. Para usar la información en cada tabla, usamos ese identificador para obtenerla indirectamente.</div>

<div><br></div><div>He aquí el quid de la cuestión de los punteros: la indirección. Por cada tipo de puntero, tantos niveles de indirección tendremos. En el ejemplo, con un doble puntero, necesitamos realizar dos "saltos" de indirección para llegar al número de tipo 'float'.</div>

<div><br></div><div>Otra forma de ver los punteros o, mejor dicho, las direcciones de memoria es que la memoria principal (RAM) es como un array gigantesco, y cada dirección de memoria actúa como un índice, para tal array. Por lo tanto, cada vez que usemos un puntero doble, triple, etc., realmente lo vamos a usar como un índice doble, triple, etc.; o sea, un índice a un índice a un índice, y así sucesivamente.</div>

<div><br></div><div><br></div><div>Espero que todo esto te aclare las dudas.</div><div><br></div><div>Steven</div><div><br></div></div></div></div>