Foros del Web » Programación para mayores de 30 ;) » C/C++ »

[SOLUCIONADO] Limpiar columna en matriz de dos dimensiones

Estas en el tema de Limpiar columna en matriz de dos dimensiones en el foro de C/C++ en Foros del Web. Hola, tengo esta espina hace más de medio año, ojalá me puedan ayudar a comprender el tema. No comprendo como es que funciona la siguiente ...
  #1 (permalink)  
Antiguo 09/09/2015, 20:51
 
Fecha de Ingreso: octubre-2008
Mensajes: 66
Antigüedad: 15 años, 5 meses
Puntos: 1
Limpiar columna en matriz de dos dimensiones

Hola,
tengo esta espina hace más de medio año, ojalá me puedan ayudar a comprender el tema.
No comprendo como es que funciona la siguiente linea:

Código:
(*p)[i] = 0;
comprendida en el siguiente código:

Código:
int mat[num_filas][num_columnas], (*p)[num_columnas], i; 
for(p = &mat[0]; p < &mat[num_filas]; p++) 
(*p)[i] = 0;
Según mi libro, este for limpia la columna i de la matriz. Entiendo que p es un puntero a un array de enteros de tamaño num_columnas. Entiendo que en el for le asigna la primera fila de la matriz al puntero, comprueba que sea menor o igual a la ultima fila, y aumenta p de fila en fila. Y entiendo que en
Código:
(*p)[i] = 0;
la i es la columna a rellenar con 0, pero lo que me confunde es el uso del valor al que apunta p, es decir (*p) con un subíndice. Además en mi libro dice que los paréntesis de (*p) son necesarios ya que sino el compilador interpretaría *(p[i]), lo cual sí que tiene sentido para mi.
  #2 (permalink)  
Antiguo 10/09/2015, 01:01
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Limpiar columna en matriz de dos dimensiones

El código que aparece a continuación se entiende, no? una matriz declarada en la pila del programa:

Código C:
Ver original
  1. int mat[num_filas][num_columnas];

Esta matriz, en memoria, se almacena por filas: 1ªfila, 2ªfila, ... esto quiere decir que cada fila va a estar compuesta por num_columnas elementos. C no necesita saber el tamaño final de la matriz... únicamente necesita saber el tamaño de cada bloque para poder calcular los saltos correctamente. Es responsabilidad del programador no leer fuera de los límites de la matriz, por lo que el programa, simplemente, pasa de hacer chequeos.

Ejemplo:
Sabiendo que cada fila se compone de n columnas, si yo pongo:

Código C:
Ver original
  1. mat[3][4] = 50;

El programa realizará la siguiente operación:

Código C:
Ver original
  1. mat[ 3 * n + 4 ] = 50

Y tiene su sentido... si queremos acceder a la 4ª fila se entiende que tenemos que saltar del tirón las 3 primeras; teniendo en cuenta que cada una de estas filas está compuesta de n elementos... al final la posición [3][4] se encontrará haciendo el cálculo 3*n+4.

¿Y esto a qué viene? ahora lo vamos a ver... ahora llega la siguiente variable:

Código C:
Ver original
  1. int (*p)[num_columnas];

Esta variable tiene un asterisco, luego es, al menos, un puntero, pero además luego tiene los corchetes por lo que se trata de un puntero doble. La peculiaridad de este puntero doble es que especifica el tamaño de cada bloque... justo lo que te he explicado antes.

Inicialmente este puntero no hace nada útil ya que no apunta a nada, sin embargo después se hace:

Código C:
Ver original
  1. for(p = &mat[0];

En esa inicialización del for se hace que nuestro puntero doble apunte al inicio de mat. Y ¡sorpresa! ambas variables tienen el mismo tamaño de bloque. ¿Ves a dónde quiero ir a parar?

Bueno, seguimos con el programa...

En la condición del for se especifica que el bucle se repetirá hasta que p apunte fuera de la matriz. &mat[num_filas] devuelve la posición de memoria del inicio de lo que sería la fila que seguiría a la última fila, o, dicho de otra forma, devuelve la primera posición de memoria que ya no pertenece a la matriz, por lo que si p apunta a una posición de memoria igual o superior es que nos hemos pasado y el bucle se dará por finalizado:

Código C:
Ver original
  1. p < &mat[num_filas]

Y bueno, en los incrementos del bucle nos encontramos con esto:

Código C:
Ver original
  1. p++

p hemos dicho que es un puntero que apunta a bloques de num_columnas elementos, luego cada incremento hará que p avance de un bloque al siguiente. Es decir, en cada incremento p avanzara num_columnas elementos

Ahora la parte final del código:

Código C:
Ver original
  1. (*p)[i] = 0;

Es incorrecta... i no está inicializada, luego tendrá un valor completamente aleatorio.

Al final el programa no funciona símplemente por esa línea. ¿Qué falta? falta un segundo for dentro del primero que haga que i recorra el intervalo [0,num_columnas). Por cierto, nota que el intervalo es abierto por la derecha. Con código quedaría tal que:

Código C:
Ver original
  1. for(p = &mat[0]; p < &mat[num_filas]; p++)
  2.     for(i=0;i<num_columnas;++i)
  3.       *p[i] = 0;

Espero haberte aclarado la duda con esta respuesta.

Un saludo.
  #3 (permalink)  
Antiguo 10/09/2015, 07:36
 
Fecha de Ingreso: octubre-2008
Mensajes: 66
Antigüedad: 15 años, 5 meses
Puntos: 1
Respuesta: Limpiar columna en matriz de dos dimensiones

Muchas gracias por tu explayada respuesta. Me ayudó a corroborar mis suposiciones. En tu última parte índicas que i no esta inicializada, con lo que estoy de acuerdo. Sin embargo suponiendo que este inicializado en algún valor, supongamos 1, el código debería funcionar sin ese segundo for que índicas; y utilizando la expresión (confusa para mi)
Código:
 (*p)[i] = 0;
así esta en mi libro, y debería colocar en 0 toda la columna 1 de cada fila.

Última edición por Virtualforos; 10/09/2015 a las 07:42
  #4 (permalink)  
Antiguo 10/09/2015, 09:09
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Limpiar columna en matriz de dos dimensiones

Sin entrar en si i está inicializada o no, la expresión:

Código C:
Ver original
  1. (*p)[i] = 0;

Únicamente puede modificar un int, ¿por qué? porque p es un puntero doble a tipo int... luego si eliminas las dos indirecciones que tiene (una se elimina con el asterisco y la otra con los corchetes) te encuentras con que estás accediendo única y exclusivamente a un entero, que es lo único que podrás modificar en ese paso.

Ahora, si resulta que tenemos en cuenta el valor de i, al no estar inicalizada, puede tener cualquier valor dentro del rango de un int, que es prácticamente (-2^31..2^31). En este caso, con la expresión anterior también estarás accediendo única y exclusivamente a un int por vez, lo que sucede es que ese int puede estar en cualquier parte de la memoria y, muy seguramente, esa memoria no pertenezca a la matriz que pretendes inicializar.

Por cierto, si te fijas verás que la inmensa mayoría de los libros de programación tienen un número de revisión. Esto es porque se descubren errores una vez publicado el libro y la única forma de corregirlos es aplicarlos en la siguiente revisión.
  #5 (permalink)  
Antiguo 11/09/2015, 21:35
 
Fecha de Ingreso: octubre-2008
Mensajes: 66
Antigüedad: 15 años, 5 meses
Puntos: 1
Respuesta: Limpiar columna en matriz de dos dimensiones

Osea p tiene almacenada la dirección de un array, el valor al que apunta esa dirección, es a su vez una dirección, la dirección del primer elemento de la fila actual. En
Código:
(*p)[i]
(*p) toma esa dirección y le suma i x el tamaño de cada elemento, en este caso ints. Entendí bien?

Etiquetas: columna, dimensiones, funcion, int, limpiar, matriz
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 18:58.